Remove the CallKind
We used to have CallKind only because there was a requirement to have all successors in a contiguous memory block. Now that the requirement is gone, remove the CallKind and instead just have the necessary information inline. Awesome!
This commit is contained in:
parent
02365fe753
commit
65dd5e6a84
6 changed files with 53 additions and 145 deletions
|
|
@ -268,71 +268,13 @@ pub enum Terminator<'tcx> {
|
|||
func: Operand<'tcx>,
|
||||
/// Arguments the function is called with
|
||||
args: Vec<Operand<'tcx>>,
|
||||
/// The kind of call with associated information
|
||||
kind: CallKind<'tcx>,
|
||||
/// Destination for the return value. If some, the call is converging.
|
||||
destination: Option<(Lvalue<'tcx>, BasicBlock)>,
|
||||
/// Cleanups to be done if the call unwinds.
|
||||
cleanup: Option<BasicBlock>
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable)]
|
||||
pub enum CallKind<'tcx> {
|
||||
/// Diverging function without associated cleanup
|
||||
Diverging,
|
||||
/// Diverging function with associated cleanup
|
||||
DivergingCleanup(BasicBlock),
|
||||
/// Converging function without associated cleanup
|
||||
Converging {
|
||||
/// Destination where the call result is written
|
||||
destination: Lvalue<'tcx>,
|
||||
/// Block to branch into on successful return
|
||||
target: BasicBlock,
|
||||
},
|
||||
ConvergingCleanup {
|
||||
/// Destination where the call result is written
|
||||
destination: Lvalue<'tcx>,
|
||||
/// First target is branched to on successful return.
|
||||
/// Second block contains the cleanups to do on unwind.
|
||||
targets: (BasicBlock, BasicBlock)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> CallKind<'tcx> {
|
||||
pub fn successors(&self) -> &[BasicBlock] {
|
||||
match *self {
|
||||
CallKind::Diverging => &[],
|
||||
CallKind::DivergingCleanup(ref b) |
|
||||
CallKind::Converging { target: ref b, .. } => slice::ref_slice(b),
|
||||
CallKind::ConvergingCleanup { ref targets, .. } => targets.as_slice(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn successors_mut(&mut self) -> &mut [BasicBlock] {
|
||||
match *self {
|
||||
CallKind::Diverging => &mut [],
|
||||
CallKind::DivergingCleanup(ref mut b) |
|
||||
CallKind::Converging { target: ref mut b, .. } => slice::mut_ref_slice(b),
|
||||
CallKind::ConvergingCleanup { ref mut targets, .. } => targets.as_mut_slice(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn destination(&self) -> Option<&Lvalue<'tcx>> {
|
||||
match *self {
|
||||
CallKind::Converging { ref destination, .. } |
|
||||
CallKind::ConvergingCleanup { ref destination, .. } => Some(destination),
|
||||
CallKind::Diverging |
|
||||
CallKind::DivergingCleanup(_) => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn destination_mut(&mut self) -> Option<&mut Lvalue<'tcx>> {
|
||||
match *self {
|
||||
CallKind::Converging { ref mut destination, .. } |
|
||||
CallKind::ConvergingCleanup { ref mut destination, .. } => Some(destination),
|
||||
CallKind::Diverging |
|
||||
CallKind::DivergingCleanup(_) => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Terminator<'tcx> {
|
||||
pub fn successors(&self) -> Cow<[BasicBlock]> {
|
||||
use self::Terminator::*;
|
||||
|
|
@ -343,7 +285,11 @@ impl<'tcx> Terminator<'tcx> {
|
|||
SwitchInt { targets: ref b, .. } => b[..].into_cow(),
|
||||
Resume => (&[]).into_cow(),
|
||||
Return => (&[]).into_cow(),
|
||||
Call { ref kind, .. } => kind.successors()[..].into_cow(),
|
||||
Call { destination: Some((_, t)), cleanup: Some(c), .. } => vec![t, c].into_cow(),
|
||||
Call { destination: Some((_, ref t)), cleanup: None, .. } =>
|
||||
slice::ref_slice(t).into_cow(),
|
||||
Call { destination: None, cleanup: Some(ref c), .. } => slice::ref_slice(c).into_cow(),
|
||||
Call { destination: None, cleanup: None, .. } => (&[]).into_cow(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -358,7 +304,10 @@ impl<'tcx> Terminator<'tcx> {
|
|||
SwitchInt { targets: ref mut b, .. } => b.iter_mut().collect(),
|
||||
Resume => Vec::new(),
|
||||
Return => Vec::new(),
|
||||
Call { ref mut kind, .. } => kind.successors_mut().iter_mut().collect(),
|
||||
Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut c), .. } => vec![t, c],
|
||||
Call { destination: Some((_, ref mut t)), cleanup: None, .. } => vec![t],
|
||||
Call { destination: None, cleanup: Some(ref mut c), .. } => vec![c],
|
||||
Call { destination: None, cleanup: None, .. } => vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -425,8 +374,8 @@ impl<'tcx> Terminator<'tcx> {
|
|||
SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv),
|
||||
Return => write!(fmt, "return"),
|
||||
Resume => write!(fmt, "resume"),
|
||||
Call { ref kind, ref func, ref args } => {
|
||||
if let Some(destination) = kind.destination() {
|
||||
Call { ref func, ref args, ref destination, .. } => {
|
||||
if let Some((ref destination, _)) = *destination {
|
||||
try!(write!(fmt, "{:?} = ", destination));
|
||||
}
|
||||
try!(write!(fmt, "{:?}(", func));
|
||||
|
|
@ -464,16 +413,11 @@ impl<'tcx> Terminator<'tcx> {
|
|||
.chain(iter::once(String::from("otherwise").into()))
|
||||
.collect()
|
||||
}
|
||||
Call { ref kind, .. } => match *kind {
|
||||
CallKind::Diverging =>
|
||||
vec![],
|
||||
CallKind::DivergingCleanup(..) =>
|
||||
vec!["unwind".into_cow()],
|
||||
CallKind::Converging { .. } =>
|
||||
vec!["return".into_cow()],
|
||||
CallKind::ConvergingCleanup { .. } =>
|
||||
vec!["return".into_cow(), "unwind".into_cow()],
|
||||
},
|
||||
Call { destination: Some(_), cleanup: Some(_), .. } =>
|
||||
vec!["return".into_cow(), "unwind".into_cow()],
|
||||
Call { destination: Some(_), cleanup: None, .. } => vec!["return".into_cow()],
|
||||
Call { destination: None, cleanup: Some(_), .. } => vec!["unwind".into_cow()],
|
||||
Call { destination: None, cleanup: None, .. } => vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -179,28 +179,17 @@ macro_rules! make_mir_visitor {
|
|||
|
||||
Terminator::Call { ref $($mutability)* func,
|
||||
ref $($mutability)* args,
|
||||
ref $($mutability)* kind } => {
|
||||
ref $($mutability)* destination,
|
||||
ref $($mutability)* cleanup } => {
|
||||
self.visit_operand(func);
|
||||
for arg in args {
|
||||
self.visit_operand(arg);
|
||||
}
|
||||
match *kind {
|
||||
CallKind::Converging {
|
||||
ref $($mutability)* destination,
|
||||
..
|
||||
} |
|
||||
CallKind::ConvergingCleanup {
|
||||
ref $($mutability)* destination,
|
||||
..
|
||||
} => {
|
||||
self.visit_lvalue(destination, LvalueContext::Store);
|
||||
}
|
||||
CallKind::Diverging |
|
||||
CallKind::DivergingCleanup(_) => {}
|
||||
}
|
||||
for &target in kind.successors() {
|
||||
if let Some((ref $($mutability)* destination, target)) = *destination {
|
||||
self.visit_lvalue(destination, LvalueContext::Store);
|
||||
self.visit_branch(block, target);
|
||||
}
|
||||
cleanup.map(|t| self.visit_branch(block, t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -253,17 +253,11 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||
this.cfg.terminate(block, Terminator::Call {
|
||||
func: fun,
|
||||
args: args,
|
||||
kind: match (cleanup, diverges) {
|
||||
(None, true) => CallKind::Diverging,
|
||||
(Some(c), true) => CallKind::DivergingCleanup(c),
|
||||
(None, false) => CallKind::Converging {
|
||||
destination: destination.clone(),
|
||||
target: success
|
||||
},
|
||||
(Some(c), false) => CallKind::ConvergingCleanup {
|
||||
destination: destination.clone(),
|
||||
targets: (success, c)
|
||||
}
|
||||
cleanup: cleanup,
|
||||
destination: if diverges {
|
||||
None
|
||||
} else {
|
||||
Some ((destination.clone(), success))
|
||||
}
|
||||
});
|
||||
success.unit()
|
||||
|
|
|
|||
|
|
@ -273,7 +273,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||
));
|
||||
let func = Constant {
|
||||
span: item.1,
|
||||
ty: tcx.lookup_item_type(item.0).ty.subst(substs),
|
||||
ty: tcx.lookup_item_type(item.0).ty,
|
||||
literal: Literal::Item {
|
||||
def_id: item.0,
|
||||
kind: ItemKind::Function,
|
||||
|
|
@ -285,10 +285,8 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||
self.cfg.terminate(new_block, Terminator::Call {
|
||||
func: Operand::Constant(func),
|
||||
args: vec![Operand::Consume(lvalue.clone())],
|
||||
kind: CallKind::Converging {
|
||||
target: old_block,
|
||||
destination: unit_tmp.clone()
|
||||
}
|
||||
destination: Some((unit_tmp.clone(), old_block)),
|
||||
cleanup: None // we’re already doing divergence cleanups
|
||||
});
|
||||
terminator = Terminator::Goto { target: new_block };
|
||||
}
|
||||
|
|
@ -383,10 +381,8 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||
self.cfg.terminate(block, Terminator::Call {
|
||||
func: Operand::Constant(func),
|
||||
args: vec![Operand::Consume(tuple_ref), index, len],
|
||||
kind: match cleanup {
|
||||
None => CallKind::Diverging,
|
||||
Some(c) => CallKind::DivergingCleanup(c)
|
||||
}
|
||||
destination: None,
|
||||
cleanup: cleanup,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -423,10 +419,8 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||
self.cfg.terminate(block, Terminator::Call {
|
||||
func: Operand::Constant(func),
|
||||
args: vec![Operand::Consume(tuple_ref)],
|
||||
kind: match cleanup {
|
||||
None => CallKind::Diverging,
|
||||
Some(c) => CallKind::DivergingCleanup(c)
|
||||
}
|
||||
cleanup: cleanup,
|
||||
destination: None,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -93,8 +93,8 @@ impl<'a, 'tcx> EraseRegions<'a, 'tcx> {
|
|||
self.erase_regions_lvalue(discr);
|
||||
*switch_ty = self.tcx.erase_regions(switch_ty);
|
||||
},
|
||||
Terminator::Call { ref mut func, ref mut args, ref mut kind } => {
|
||||
if let Some(destination) = kind.destination_mut() {
|
||||
Terminator::Call { ref mut func, ref mut args, ref mut destination, .. } => {
|
||||
if let Some((ref mut destination, _)) = *destination {
|
||||
self.erase_regions_lvalue(destination);
|
||||
}
|
||||
self.erase_regions_operand(func);
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
base::build_return_block(bcx.fcx, bcx, return_ty, DebugLoc::None);
|
||||
}
|
||||
|
||||
mir::Terminator::Call { ref func, ref args, ref kind } => {
|
||||
mir::Terminator::Call { ref func, ref args, ref destination, ref cleanup } => {
|
||||
// Create the callee. This will always be a fn ptr and hence a kind of scalar.
|
||||
let callee = self.trans_operand(bcx, func);
|
||||
let attrs = attributes::from_fn_type(bcx.ccx(), callee.ty);
|
||||
|
|
@ -115,7 +115,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
};
|
||||
|
||||
// Prepare the return value destination
|
||||
let (ret_dest_ty, must_copy_dest) = if let Some(d) = kind.destination() {
|
||||
let (ret_dest_ty, must_copy_dest) = if let Some((ref d, _)) = *destination {
|
||||
let dest = self.trans_lvalue(bcx, d);
|
||||
let ret_ty = dest.ty.to_ty(bcx.tcx());
|
||||
if !is_foreign && type_of::return_uses_outptr(bcx.ccx(), ret_ty) {
|
||||
|
|
@ -144,9 +144,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
}
|
||||
|
||||
// Many different ways to call a function handled here
|
||||
match (is_foreign, base::avoid_invoke(bcx), kind) {
|
||||
match (is_foreign, base::avoid_invoke(bcx), cleanup, destination) {
|
||||
// The two cases below are the only ones to use LLVM’s `invoke`.
|
||||
(false, false, &mir::CallKind::DivergingCleanup(cleanup)) => {
|
||||
(false, false, &Some(cleanup), &None) => {
|
||||
let cleanup = self.bcx(cleanup);
|
||||
let landingpad = self.make_landing_pad(cleanup);
|
||||
let unreachable_blk = self.unreachable_block();
|
||||
|
|
@ -158,14 +158,13 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
Some(attrs),
|
||||
debugloc);
|
||||
},
|
||||
(false, false, &mir::CallKind::ConvergingCleanup { ref targets, .. }) => {
|
||||
let cleanup = self.bcx(targets.1);
|
||||
(false, false, &Some(cleanup), &Some((_, success))) => {
|
||||
let cleanup = self.bcx(cleanup);
|
||||
let landingpad = self.make_landing_pad(cleanup);
|
||||
let (target, postinvoke) = if must_copy_dest {
|
||||
(bcx.fcx.new_block("", None),
|
||||
Some(self.bcx(targets.0)))
|
||||
(bcx.fcx.new_block("", None), Some(self.bcx(success)))
|
||||
} else {
|
||||
(self.bcx(targets.0), None)
|
||||
(self.bcx(success), None)
|
||||
};
|
||||
let invokeret = build::Invoke(bcx,
|
||||
callee.immediate(),
|
||||
|
|
@ -205,19 +204,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
build::Br(target, postinvoketarget.llbb, debugloc);
|
||||
}
|
||||
},
|
||||
(false, _, &mir::CallKind::DivergingCleanup(_)) |
|
||||
(false, _, &mir::CallKind::Diverging) => {
|
||||
(false, _, _, &None) => {
|
||||
build::Call(bcx, callee.immediate(), &llargs[..], Some(attrs), debugloc);
|
||||
build::Unreachable(bcx);
|
||||
}
|
||||
(false, _, k@&mir::CallKind::ConvergingCleanup { .. }) |
|
||||
(false, _, k@&mir::CallKind::Converging { .. }) => {
|
||||
// FIXME: Bug #20046
|
||||
let target = match *k {
|
||||
mir::CallKind::ConvergingCleanup { targets, .. } => targets.0,
|
||||
mir::CallKind::Converging { target, .. } => target,
|
||||
_ => unreachable!()
|
||||
};
|
||||
(false, _, _, &Some((_, target))) => {
|
||||
let llret = build::Call(bcx,
|
||||
callee.immediate(),
|
||||
&llargs[..],
|
||||
|
|
@ -231,7 +222,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
build::Br(bcx, self.llblock(target), debugloc);
|
||||
}
|
||||
// Foreign functions
|
||||
(true, _, k) => {
|
||||
(true, _, _, destination) => {
|
||||
let (dest, _) = ret_dest_ty
|
||||
.expect("return destination is not set");
|
||||
bcx = foreign::trans_native_call(bcx,
|
||||
|
|
@ -241,13 +232,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
&llargs[..],
|
||||
arg_tys,
|
||||
debugloc);
|
||||
match *k {
|
||||
mir::CallKind::ConvergingCleanup { targets, .. } =>
|
||||
build::Br(bcx, self.llblock(targets.0), debugloc),
|
||||
mir::CallKind::Converging { target, .. } =>
|
||||
build::Br(bcx, self.llblock(target), debugloc),
|
||||
_ => ()
|
||||
};
|
||||
if let Some((_, target)) = *destination {
|
||||
build::Br(bcx, self.llblock(target), debugloc);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue