Skip to content

Commit

Permalink
Auto merge of #29588 - nikomatsakis:mir-switch, r=aatch
Browse files Browse the repository at this point in the history
Introduce a `SwitchInt` and restructure pattern matching to collect integers and characters into one master switch. This is aimed at #29227, but is not a complete fix. Whereas before we generated an if-else-if chain and, at least on my machine, just failed to compile, we now spend ~9sec compiling `rustc_abuse`. AFAICT this is basically just due to a need for more micro-optimization of the matching process: perf shows a fair amount of time just spent iterating over the candidate list. Still, it seemed worth opening a PR with this step alone, since it's a big step forward.
  • Loading branch information
bors committed Nov 6, 2015
2 parents 7512808 + dcf323e commit 98fa2ac
Show file tree
Hide file tree
Showing 6 changed files with 319 additions and 74 deletions.
19 changes: 19 additions & 0 deletions src/librustc/middle/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use std::borrow::{Cow, IntoCow};
use std::num::wrapping::OverflowingOps;
use std::cmp::Ordering;
use std::collections::hash_map::Entry::Vacant;
use std::hash;
use std::mem::transmute;
use std::{i8, i16, i32, i64, u8, u16, u32, u64};
use std::rc::Rc;
Expand Down Expand Up @@ -257,6 +258,22 @@ pub enum ConstVal {
Function(DefId),
}

impl hash::Hash for ConstVal {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
match *self {
Float(a) => unsafe { transmute::<_,u64>(a) }.hash(state),
Int(a) => a.hash(state),
Uint(a) => a.hash(state),
Str(ref a) => a.hash(state),
ByteStr(ref a) => a.hash(state),
Bool(a) => a.hash(state),
Struct(a) => a.hash(state),
Tuple(a) => a.hash(state),
Function(a) => a.hash(state),
}
}
}

/// Note that equality for `ConstVal` means that the it is the same
/// constant, not that the rust values are equal. In particular, `NaN
/// == NaN` (at least if it's the same NaN; distinct encodings for NaN
Expand All @@ -278,6 +295,8 @@ impl PartialEq for ConstVal {
}
}

impl Eq for ConstVal { }

impl ConstVal {
pub fn description(&self) -> &'static str {
match *self {
Expand Down
41 changes: 33 additions & 8 deletions src/librustc_mir/build/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

use build::{BlockAnd, Builder};
use repr::*;
use rustc_data_structures::fnv::FnvHashMap;
use rustc::middle::const_eval::ConstVal;
use rustc::middle::region::CodeExtent;
use rustc::middle::ty::{AdtDef, Ty};
use hair::*;
Expand Down Expand Up @@ -241,6 +243,13 @@ enum TestKind<'tcx> {
adt_def: AdtDef<'tcx>,
},

// test the branches of enum
SwitchInt {
switch_ty: Ty<'tcx>,
options: Vec<ConstVal>,
indices: FnvHashMap<ConstVal, usize>,
},

// test for equality
Eq {
value: Literal<'tcx>,
Expand Down Expand Up @@ -315,20 +324,36 @@ impl<'a,'tcx> Builder<'a,'tcx> {

// otherwise, extract the next match pair and construct tests
let match_pair = &candidates.last().unwrap().match_pairs[0];
let test = self.test(match_pair);
let mut test = self.test(match_pair);

// most of the time, the test to perform is simply a function
// of the main candidate; but for a test like SwitchInt, we
// may want to add cases based on the candidates that are
// available
match test.kind {
TestKind::SwitchInt { switch_ty, ref mut options, ref mut indices } => {
for candidate in &candidates {
self.add_cases_to_switch(&match_pair.lvalue,
candidate,
switch_ty,
options,
indices);
}
}
_ => { }
}

debug!("match_candidates: test={:?} match_pair={:?}", test, match_pair);
let target_blocks = self.perform_test(block, &match_pair.lvalue, &test);

for (outcome, mut target_block) in target_blocks.into_iter().enumerate() {
for (outcome, target_block) in target_blocks.into_iter().enumerate() {
let applicable_candidates: Vec<Candidate<'tcx>> =
candidates.iter()
.filter_map(|candidate| {
unpack!(target_block =
self.candidate_under_assumption(target_block,
&match_pair.lvalue,
&test.kind,
outcome,
candidate))
self.candidate_under_assumption(&match_pair.lvalue,
&test.kind,
outcome,
candidate)
})
.collect();
self.match_candidates(span, arm_blocks, applicable_candidates, target_block);
Expand Down
Loading

0 comments on commit 98fa2ac

Please sign in to comment.