Skip to content

Commit 1355a57

Browse files
committed
SwitchInt over Switch
This removes another special case of Switch by replacing it with the more general SwitchInt. While this is more clunky currently, there’s no reason we can’t make it nice (and efficient) to use.
1 parent a8075a4 commit 1355a57

File tree

19 files changed

+105
-128
lines changed

19 files changed

+105
-128
lines changed

src/librustc/middle/const_val.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use std::rc::Rc;
1414
use hir::def_id::DefId;
1515
use rustc_const_math::*;
1616
use self::ConstVal::*;
17+
pub use rustc_const_math::ConstInt;
1718

1819
use std::collections::BTreeMap;
1920

src/librustc/mir/mod.rs

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -453,13 +453,6 @@ pub enum TerminatorKind<'tcx> {
453453
target: BasicBlock,
454454
},
455455

456-
/// lvalue evaluates to some enum; jump depending on the branch
457-
Switch {
458-
discr: Lvalue<'tcx>,
459-
adt_def: &'tcx AdtDef,
460-
targets: Vec<BasicBlock>,
461-
},
462-
463456
/// operand evaluates to an integer; jump depending on its value
464457
/// to one of the targets, and otherwise fallback to `otherwise`
465458
SwitchInt {
@@ -471,6 +464,7 @@ pub enum TerminatorKind<'tcx> {
471464

472465
/// Possible values. The locations to branch to in each case
473466
/// are found in the corresponding indices from the `targets` vector.
467+
// FIXME: ConstVal doesn’t quite make any sense here? Its a Switch*Int*.
474468
values: Vec<ConstVal>,
475469

476470
/// Possible branch sites. The length of this vector should be
@@ -544,7 +538,6 @@ impl<'tcx> TerminatorKind<'tcx> {
544538
use self::TerminatorKind::*;
545539
match *self {
546540
Goto { target: ref b } => slice::ref_slice(b).into_cow(),
547-
Switch { targets: ref b, .. } => b[..].into_cow(),
548541
SwitchInt { targets: ref b, .. } => b[..].into_cow(),
549542
Resume => (&[]).into_cow(),
550543
Return => (&[]).into_cow(),
@@ -573,7 +566,6 @@ impl<'tcx> TerminatorKind<'tcx> {
573566
use self::TerminatorKind::*;
574567
match *self {
575568
Goto { target: ref mut b } => vec![b],
576-
Switch { targets: ref mut b, .. } => b.iter_mut().collect(),
577569
SwitchInt { targets: ref mut b, .. } => b.iter_mut().collect(),
578570
Resume => Vec::new(),
579571
Return => Vec::new(),
@@ -651,7 +643,6 @@ impl<'tcx> TerminatorKind<'tcx> {
651643
use self::TerminatorKind::*;
652644
match *self {
653645
Goto { .. } => write!(fmt, "goto"),
654-
Switch { discr: ref lv, .. } => write!(fmt, "switch({:?})", lv),
655646
SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv),
656647
Return => write!(fmt, "return"),
657648
Resume => write!(fmt, "resume"),
@@ -701,12 +692,6 @@ impl<'tcx> TerminatorKind<'tcx> {
701692
match *self {
702693
Return | Resume | Unreachable => vec![],
703694
Goto { .. } => vec!["".into()],
704-
Switch { ref adt_def, .. } => {
705-
adt_def.variants
706-
.iter()
707-
.map(|variant| variant.name.to_string().into())
708-
.collect()
709-
}
710695
SwitchInt { ref values, .. } => {
711696
values.iter()
712697
.map(|const_val| {

src/librustc/mir/tcx.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use mir::*;
1717
use ty::subst::{Subst, Substs};
1818
use ty::{self, AdtDef, Ty, TyCtxt};
1919
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
20+
use syntax::attr;
2021
use hir;
2122

2223
#[derive(Copy, Clone, Debug)]
@@ -170,9 +171,14 @@ impl<'tcx> Rvalue<'tcx> {
170171
Some(operand.ty(mir, tcx))
171172
}
172173
Rvalue::Discriminant(ref lval) => {
173-
if let ty::TyAdt(_, _) = lval.ty(mir, tcx).to_ty(tcx).sty {
174-
// TODO
175-
None
174+
if let ty::TyAdt(adt_def, _) = lval.ty(mir, tcx).to_ty(tcx).sty {
175+
// FIXME: Why this does not work?
176+
// Some(adt_def.discr_ty.to_ty(tcx))
177+
let ty = match adt_def.discr_ty {
178+
attr::SignedInt(i) => tcx.mk_mach_int(i),
179+
attr::UnsignedInt(i) => tcx.mk_mach_uint(i),
180+
};
181+
Some(ty)
176182
} else {
177183
None
178184
}

src/librustc/mir/visit.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -362,15 +362,6 @@ macro_rules! make_mir_visitor {
362362
self.visit_branch(block, target);
363363
}
364364

365-
TerminatorKind::Switch { ref $($mutability)* discr,
366-
adt_def: _,
367-
ref targets } => {
368-
self.visit_lvalue(discr, LvalueContext::Inspect, source_location);
369-
for &target in targets {
370-
self.visit_branch(block, target);
371-
}
372-
}
373-
374365
TerminatorKind::SwitchInt { ref $($mutability)* discr,
375366
ref $($mutability)* switch_ty,
376367
ref $($mutability)* values,

src/librustc/ty/util.rs

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,27 +39,17 @@ use rustc_i128::i128;
3939
use hir;
4040

4141
pub trait IntTypeExt {
42-
fn to_ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx>;
42+
fn to_ty<'a, 'tcx>(self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx>;
4343
fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Disr>)
4444
-> Option<Disr>;
4545
fn initial_discriminant<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>) -> Disr;
4646
}
4747

4848
impl IntTypeExt for attr::IntType {
49-
fn to_ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
50-
match *self {
51-
SignedInt(ast::IntTy::I8) => tcx.types.i8,
52-
SignedInt(ast::IntTy::I16) => tcx.types.i16,
53-
SignedInt(ast::IntTy::I32) => tcx.types.i32,
54-
SignedInt(ast::IntTy::I64) => tcx.types.i64,
55-
SignedInt(ast::IntTy::I128) => tcx.types.i128,
56-
SignedInt(ast::IntTy::Is) => tcx.types.isize,
57-
UnsignedInt(ast::UintTy::U8) => tcx.types.u8,
58-
UnsignedInt(ast::UintTy::U16) => tcx.types.u16,
59-
UnsignedInt(ast::UintTy::U32) => tcx.types.u32,
60-
UnsignedInt(ast::UintTy::U64) => tcx.types.u64,
61-
UnsignedInt(ast::UintTy::U128) => tcx.types.u128,
62-
UnsignedInt(ast::UintTy::Us) => tcx.types.usize,
49+
fn to_ty<'a, 'gcx, 'tcx>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
50+
match self {
51+
SignedInt(i) => tcx.mk_mach_int(i),
52+
UnsignedInt(i) => tcx.mk_mach_uint(i),
6353
}
6454
}
6555

src/librustc_borrowck/borrowck/mir/dataflow/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,6 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D>
454454
self.propagate_bits_into_entry_set_for(in_out, changed, target);
455455
self.propagate_bits_into_entry_set_for(in_out, changed, unwind);
456456
}
457-
mir::TerminatorKind::Switch { ref targets, .. } |
458457
mir::TerminatorKind::SwitchInt { ref targets, .. } => {
459458
for target in targets {
460459
self.propagate_bits_into_entry_set_for(in_out, changed, target);

src/librustc_borrowck/borrowck/mir/elaborate_drops.rs

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ use super::{DropFlagState, MoveDataParamEnv};
1717
use super::patch::MirPatch;
1818
use rustc::ty::{self, Ty, TyCtxt};
1919
use rustc::ty::subst::{Kind, Subst, Substs};
20+
use rustc::ty::util::IntTypeExt;
2021
use rustc::mir::*;
2122
use rustc::mir::transform::{Pass, MirPass, MirSource};
22-
use rustc::middle::const_val::ConstVal;
23+
use rustc::middle::const_val::{ConstVal, ConstInt};
2324
use rustc::middle::lang_items;
2425
use rustc::util::nodemap::FxHashMap;
2526
use rustc_data_structures::indexed_set::IdxSetBuf;
@@ -672,27 +673,45 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
672673
self.drop_ladder(c, fields)
673674
}
674675
_ => {
675-
let variant_drops : Vec<BasicBlock> =
676-
(0..adt.variants.len()).map(|i| {
677-
self.open_drop_for_variant(c, &mut drop_block,
678-
adt, substs, i)
679-
}).collect();
680-
676+
let mut values = Vec::with_capacity(adt.variants.len());
677+
let mut blocks = Vec::with_capacity(adt.variants.len() + 1);
678+
for (idx, variant) in adt.variants.iter().enumerate() {
679+
let discr = ConstInt::new_inttype(variant.disr_val, adt.discr_ty,
680+
self.tcx.sess.target.uint_type,
681+
self.tcx.sess.target.int_type).unwrap();
682+
values.push(ConstVal::Integral(discr));
683+
blocks.push(self.open_drop_for_variant(c, &mut drop_block, adt, substs, idx));
684+
}
681685
// If there are multiple variants, then if something
682686
// is present within the enum the discriminant, tracked
683687
// by the rest path, must be initialized.
684688
//
685689
// Additionally, we do not want to switch on the
686690
// discriminant after it is free-ed, because that
687691
// way lies only trouble.
688-
689-
let switch_block = self.new_block(
690-
c, c.is_cleanup, TerminatorKind::Switch {
691-
discr: c.lvalue.clone(),
692-
adt_def: adt,
693-
targets: variant_drops
694-
});
695-
692+
let discr_ty = adt.discr_ty.to_ty(self.tcx);
693+
let discr = Lvalue::Local(self.patch.new_temp(discr_ty));
694+
let switch_block = self.patch.new_block(BasicBlockData {
695+
statements: vec![
696+
Statement {
697+
source_info: c.source_info,
698+
kind: StatementKind::Assign(discr.clone(),
699+
Rvalue::Discriminant(c.lvalue.clone()))
700+
}
701+
],
702+
terminator: Some(Terminator {
703+
source_info: c.source_info,
704+
kind: TerminatorKind::SwitchInt {
705+
discr: Operand::Consume(discr),
706+
switch_ty: discr_ty,
707+
values: values,
708+
targets: blocks,
709+
// adt_def: adt,
710+
// targets: variant_drops
711+
}
712+
}),
713+
is_cleanup: c.is_cleanup,
714+
});
696715
self.drop_flag_test_block(c, switch_block)
697716
}
698717
}

src/librustc_borrowck/borrowck/mir/gather_moves.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -465,8 +465,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
465465
}
466466

467467
TerminatorKind::Assert { .. } |
468-
TerminatorKind::SwitchInt { .. } |
469-
TerminatorKind::Switch { .. } => {
468+
TerminatorKind::SwitchInt { .. } => {
470469
// branching terminators - these don't move anything
471470
}
472471

src/librustc_const_math/int.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ mod ibounds {
7777
}
7878

7979
impl ConstInt {
80+
pub fn new_inttype(val: u128, ty: IntType, usize_ty: UintTy, isize_ty: IntTy)
81+
-> Option<ConstInt> {
82+
match ty {
83+
IntType::SignedInt(i) => ConstInt::new_signed(val as i128, i, isize_ty),
84+
IntType::UnsignedInt(i) => ConstInt::new_unsigned(val, i, usize_ty),
85+
}
86+
}
87+
8088
/// Creates a new unsigned ConstInt with matching type while also checking that overflow does
8189
/// not happen.
8290
pub fn new_unsigned(val: u128, ty: UintTy, usize_ty: UintTy) -> Option<ConstInt> {

src/librustc_data_structures/bitvec.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ impl BitVector {
3030
}
3131
}
3232

33+
pub fn count(&self) -> usize {
34+
self.data.iter().map(|e| e.count_ones() as usize).sum()
35+
}
36+
3337
#[inline]
3438
pub fn contains(&self, bit: usize) -> bool {
3539
let (word, mask) = word_mask(bit);

src/librustc_mir/build/matches/test.rs

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@ use build::matches::{Candidate, MatchPair, Test, TestKind};
2020
use hair::*;
2121
use rustc_data_structures::fx::FxHashMap;
2222
use rustc_data_structures::bitvec::BitVector;
23-
use rustc::middle::const_val::ConstVal;
23+
use rustc::middle::const_val::{ConstVal, ConstInt};
2424
use rustc::ty::{self, Ty};
2525
use rustc::mir::*;
2626
use rustc::hir::RangeEnd;
2727
use syntax_pos::Span;
28+
use syntax::attr;
2829
use std::cmp::Ordering;
2930

3031
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
@@ -182,24 +183,51 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
182183
let source_info = self.source_info(test.span);
183184
match test.kind {
184185
TestKind::Switch { adt_def, ref variants } => {
186+
// Variants is a BitVec of indexes into adt_def.variants.
185187
let num_enum_variants = self.hir.num_variants(adt_def);
188+
let used_variants = variants.count();
186189
let mut otherwise_block = None;
187-
let target_blocks: Vec<_> = (0..num_enum_variants).map(|i| {
188-
if variants.contains(i) {
189-
self.cfg.start_new_block()
190+
let mut target_blocks = Vec::with_capacity(num_enum_variants);
191+
let mut targets = Vec::with_capacity(used_variants + 1);
192+
let mut values = Vec::with_capacity(used_variants);
193+
let tcx = self.hir.tcx();
194+
for (idx, variant) in adt_def.variants.iter().enumerate() {
195+
target_blocks.place_back() <- if variants.contains(idx) {
196+
let discr = ConstInt::new_inttype(variant.disr_val, adt_def.discr_ty,
197+
tcx.sess.target.uint_type,
198+
tcx.sess.target.int_type).unwrap();
199+
values.push(ConstVal::Integral(discr));
200+
*(targets.place_back() <- self.cfg.start_new_block())
190201
} else {
191202
if otherwise_block.is_none() {
192203
otherwise_block = Some(self.cfg.start_new_block());
193204
}
194205
otherwise_block.unwrap()
195-
}
196-
}).collect();
197-
debug!("num_enum_variants: {}, num tested variants: {}, variants: {:?}",
198-
num_enum_variants, variants.iter().count(), variants);
199-
self.cfg.terminate(block, source_info, TerminatorKind::Switch {
200-
discr: lvalue.clone(),
201-
adt_def: adt_def,
202-
targets: target_blocks.clone()
206+
};
207+
}
208+
if let Some(otherwise_block) = otherwise_block {
209+
targets.push(otherwise_block);
210+
} else {
211+
values.pop();
212+
}
213+
debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}",
214+
num_enum_variants, values, variants);
215+
// FIXME: WHY THIS DOES NOT WORK?!
216+
// let discr_ty = adt_def.discr_ty.to_ty(tcx);
217+
let discr_ty = match adt_def.discr_ty {
218+
attr::SignedInt(i) => tcx.mk_mach_int(i),
219+
attr::UnsignedInt(i) => tcx.mk_mach_uint(i),
220+
};
221+
222+
let discr = self.temp(discr_ty);
223+
self.cfg.push_assign(block, source_info, &discr,
224+
Rvalue::Discriminant(lvalue.clone()));
225+
assert_eq!(values.len() + 1, targets.len());
226+
self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
227+
discr: Operand::Consume(discr),
228+
switch_ty: discr_ty,
229+
values: values,
230+
targets: targets
203231
});
204232
target_blocks
205233
}

src/librustc_mir/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
2626
#![feature(rustc_diagnostic_macros)]
2727
#![feature(rustc_private)]
2828
#![feature(staged_api)]
29+
#![feature(placement_in_syntax)]
30+
#![feature(collection_placement)]
2931

3032
#[macro_use] extern crate log;
3133
extern crate graphviz as dot;

src/librustc_mir/transform/no_landing_pads.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
2828
TerminatorKind::Resume |
2929
TerminatorKind::Return |
3030
TerminatorKind::Unreachable |
31-
TerminatorKind::Switch { .. } |
3231
TerminatorKind::SwitchInt { .. } => {
3332
/* nothing to do */
3433
},

src/librustc_mir/transform/qualify_consts.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,6 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
394394
return Qualif::empty();
395395
}
396396

397-
TerminatorKind::Switch {..} |
398397
TerminatorKind::SwitchInt {..} |
399398
TerminatorKind::DropAndReplace { .. } |
400399
TerminatorKind::Resume |

src/librustc_mir/transform/simplify.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,6 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> {
209209
// turn a branch with all successors identical to a goto
210210
fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool {
211211
match terminator.kind {
212-
TerminatorKind::Switch { .. } |
213212
TerminatorKind::SwitchInt { .. } => {},
214213
_ => return false
215214
};

src/librustc_mir/transform/type_check.rs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -436,19 +436,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
436436
}
437437
// FIXME: check the values
438438
}
439-
TerminatorKind::Switch { ref discr, adt_def, ref targets } => {
440-
let discr_ty = discr.ty(mir, tcx).to_ty(tcx);
441-
match discr_ty.sty {
442-
ty::TyAdt(def, _) if def.is_enum() &&
443-
def == adt_def &&
444-
adt_def.variants.len() == targets.len()
445-
=> {},
446-
_ => {
447-
span_mirbug!(self, term, "bad Switch ({:?} on {:?})",
448-
adt_def, discr_ty);
449-
}
450-
}
451-
}
452439
TerminatorKind::Call { ref func, ref args, ref destination, .. } => {
453440
let func_ty = func.ty(mir, tcx);
454441
debug!("check_terminator: call, func_ty={:?}", func_ty);
@@ -593,7 +580,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
593580
match block.terminator().kind {
594581
TerminatorKind::Goto { target } =>
595582
self.assert_iscleanup(mir, block, target, is_cleanup),
596-
TerminatorKind::Switch { ref targets, .. } |
597583
TerminatorKind::SwitchInt { ref targets, .. } => {
598584
for target in targets {
599585
self.assert_iscleanup(mir, block, *target, is_cleanup);

0 commit comments

Comments
 (0)