Add TerminatorKind::if_ convenience constructor

Constructs a TerminatorKind::SwitchInt for an equivalent conditional true-false branch.
This commit is contained in:
Simonas Kazlauskas 2017-02-03 03:36:32 +02:00
parent a8b7b62185
commit eb727a8faa
5 changed files with 38 additions and 62 deletions

View File

@ -446,9 +446,6 @@ pub struct Terminator<'tcx> {
pub kind: TerminatorKind<'tcx>
}
/// For use in SwitchInt, for switching on bools.
pub static BOOL_SWITCH_FALSE: Cow<'static, [ConstInt]> = Cow::Borrowed(&[ConstInt::Infer(0)]);
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub enum TerminatorKind<'tcx> {
/// block should have one successor in the graph; we jump there
@ -543,6 +540,17 @@ impl<'tcx> Terminator<'tcx> {
}
impl<'tcx> TerminatorKind<'tcx> {
pub fn if_<'a, 'gcx>(tcx: ty::TyCtxt<'a, 'gcx, 'tcx>, cond: Operand<'tcx>,
t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> {
static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::Infer(0)];
TerminatorKind::SwitchInt {
discr: cond,
switch_ty: tcx.types.bool,
values: From::from(BOOL_SWITCH_FALSE),
targets: vec![f, t],
}
}
pub fn successors(&self) -> Cow<[BasicBlock]> {
use self::TerminatorKind::*;
match *self {

View File

@ -842,13 +842,8 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
(true, false) => on_set,
(true, true) => {
let flag = self.drop_flag(c.path).unwrap();
let boolty = self.tcx.types.bool;
self.new_block(c, is_cleanup, TerminatorKind::SwitchInt {
discr: Operand::Consume(flag),
switch_ty: boolty,
values: BOOL_SWITCH_FALSE.clone(),
targets: vec![on_unset, on_set],
})
let term = TerminatorKind::if_(self.tcx, Operand::Consume(flag), on_set, on_unset);
self.new_block(c, is_cleanup, term)
}
}
}

View File

@ -69,12 +69,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let mut then_block = this.cfg.start_new_block();
let mut else_block = this.cfg.start_new_block();
this.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
discr: operand,
switch_ty: this.hir.bool_ty(),
values: BOOL_SWITCH_FALSE.clone(),
targets: vec![else_block, then_block],
});
let term = TerminatorKind::if_(this.hir.tcx(), operand, then_block, else_block);
this.cfg.terminate(block, source_info, term);
unpack!(then_block = this.into(destination, then_block, then_expr));
else_block = if let Some(else_expr) = else_expr {
@ -113,23 +109,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let lhs = unpack!(block = this.as_operand(block, lhs));
let blocks = match op {
LogicalOp::And => vec![false_block, else_block],
LogicalOp::Or => vec![else_block, true_block],
LogicalOp::And => (else_block, false_block),
LogicalOp::Or => (true_block, else_block),
};
this.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
discr: lhs,
switch_ty: this.hir.bool_ty(),
values: BOOL_SWITCH_FALSE.clone(),
targets: blocks,
});
let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1);
this.cfg.terminate(block, source_info, term);
let rhs = unpack!(else_block = this.as_operand(else_block, rhs));
this.cfg.terminate(else_block, source_info, TerminatorKind::SwitchInt {
discr: rhs,
switch_ty: this.hir.bool_ty(),
values: BOOL_SWITCH_FALSE.clone(),
targets: vec![false_block, true_block],
});
let term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block);
this.cfg.terminate(else_block, source_info, term);
this.cfg.push_assign_constant(
true_block, source_info, destination,
@ -187,13 +175,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let cond = unpack!(
loop_block_end = this.as_operand(loop_block, cond_expr));
body_block = this.cfg.start_new_block();
this.cfg.terminate(loop_block_end, source_info,
TerminatorKind::SwitchInt {
discr: cond,
switch_ty: this.hir.bool_ty(),
values: BOOL_SWITCH_FALSE.clone(),
targets: vec![exit_block, body_block],
});
let term = TerminatorKind::if_(this.hir.tcx(), cond,
body_block, exit_block);
this.cfg.terminate(loop_block_end, source_info, term);
// if the test is false, there's no `break` to assign `destination`, so
// we have to do it; this overwrites any `break`-assigned value but it's

View File

@ -672,12 +672,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let source_info = self.source_info(guard.span);
let cond = unpack!(block = self.as_operand(block, guard));
let otherwise = self.cfg.start_new_block();
self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
discr: cond,
switch_ty: self.hir.bool_ty(),
values: BOOL_SWITCH_FALSE.clone(),
targets: vec![otherwise, arm_block],
});
self.cfg.terminate(block, source_info,
TerminatorKind::if_(self.hir.tcx(), cond, arm_block, otherwise));
Some(otherwise)
} else {
let source_info = self.source_info(candidate.span);

View File

@ -228,6 +228,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
TestKind::SwitchInt { switch_ty, ref options, indices: _ } => {
let (values, targets, ret) = if switch_ty.sty == ty::TyBool {
static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::Infer(0)];
assert!(options.len() > 0 && options.len() <= 2);
let (true_bb, false_bb) = (self.cfg.start_new_block(),
self.cfg.start_new_block());
@ -236,7 +237,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
&ConstVal::Bool(false) => vec![false_bb, true_bb],
v => span_bug!(test.span, "expected boolean value but got {:?}", v)
};
(BOOL_SWITCH_FALSE.clone(), vec![false_bb, true_bb], ret)
(From::from(BOOL_SWITCH_FALSE), vec![false_bb, true_bb], ret)
} else {
// The switch may be inexhaustive so we
// add a catch all block
@ -323,12 +324,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// check the result
let block = self.cfg.start_new_block();
self.cfg.terminate(eq_block, source_info, TerminatorKind::SwitchInt {
discr: Operand::Consume(eq_result),
switch_ty: self.hir.bool_ty(),
values: BOOL_SWITCH_FALSE.clone(),
targets: vec![fail, block],
});
self.cfg.terminate(eq_block, source_info,
TerminatorKind::if_(self.hir.tcx(),
Operand::Consume(eq_result),
block, fail));
vec![block, fail]
} else {
let block = self.compare(block, fail, test.span, BinOp::Eq, expect, val);
@ -372,12 +371,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// branch based on result
let (false_bb, true_bb) = (self.cfg.start_new_block(),
self.cfg.start_new_block());
self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
discr: Operand::Consume(result),
switch_ty: self.hir.bool_ty(),
values: BOOL_SWITCH_FALSE.clone(),
targets: vec![false_bb, true_bb],
});
self.cfg.terminate(block, source_info,
TerminatorKind::if_(self.hir.tcx(), Operand::Consume(result),
true_bb, false_bb));
vec![true_bb, false_bb]
}
}
@ -400,12 +396,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// branch based on result
let target_block = self.cfg.start_new_block();
self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
discr: Operand::Consume(result),
switch_ty: self.hir.bool_ty(),
values: BOOL_SWITCH_FALSE.clone(),
targets: vec![fail_block, target_block]
});
self.cfg.terminate(block, source_info,
TerminatorKind::if_(self.hir.tcx(), Operand::Consume(result),
target_block, fail_block));
target_block
}