Skip to content

Commit 98fa2ac

Browse files
committed
Auto merge of #29588 - nikomatsakis:mir-switch, r=aatch
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.
2 parents 7512808 + dcf323e commit 98fa2ac

File tree

6 files changed

+319
-74
lines changed

6 files changed

+319
-74
lines changed

src/librustc/middle/const_eval.rs

+19
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use std::borrow::{Cow, IntoCow};
3939
use std::num::wrapping::OverflowingOps;
4040
use std::cmp::Ordering;
4141
use std::collections::hash_map::Entry::Vacant;
42+
use std::hash;
4243
use std::mem::transmute;
4344
use std::{i8, i16, i32, i64, u8, u16, u32, u64};
4445
use std::rc::Rc;
@@ -257,6 +258,22 @@ pub enum ConstVal {
257258
Function(DefId),
258259
}
259260

261+
impl hash::Hash for ConstVal {
262+
fn hash<H: hash::Hasher>(&self, state: &mut H) {
263+
match *self {
264+
Float(a) => unsafe { transmute::<_,u64>(a) }.hash(state),
265+
Int(a) => a.hash(state),
266+
Uint(a) => a.hash(state),
267+
Str(ref a) => a.hash(state),
268+
ByteStr(ref a) => a.hash(state),
269+
Bool(a) => a.hash(state),
270+
Struct(a) => a.hash(state),
271+
Tuple(a) => a.hash(state),
272+
Function(a) => a.hash(state),
273+
}
274+
}
275+
}
276+
260277
/// Note that equality for `ConstVal` means that the it is the same
261278
/// constant, not that the rust values are equal. In particular, `NaN
262279
/// == NaN` (at least if it's the same NaN; distinct encodings for NaN
@@ -278,6 +295,8 @@ impl PartialEq for ConstVal {
278295
}
279296
}
280297

298+
impl Eq for ConstVal { }
299+
281300
impl ConstVal {
282301
pub fn description(&self) -> &'static str {
283302
match *self {

src/librustc_mir/build/matches/mod.rs

+33-8
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
1616
use build::{BlockAnd, Builder};
1717
use repr::*;
18+
use rustc_data_structures::fnv::FnvHashMap;
19+
use rustc::middle::const_eval::ConstVal;
1820
use rustc::middle::region::CodeExtent;
1921
use rustc::middle::ty::{AdtDef, Ty};
2022
use hair::*;
@@ -241,6 +243,13 @@ enum TestKind<'tcx> {
241243
adt_def: AdtDef<'tcx>,
242244
},
243245

246+
// test the branches of enum
247+
SwitchInt {
248+
switch_ty: Ty<'tcx>,
249+
options: Vec<ConstVal>,
250+
indices: FnvHashMap<ConstVal, usize>,
251+
},
252+
244253
// test for equality
245254
Eq {
246255
value: Literal<'tcx>,
@@ -315,20 +324,36 @@ impl<'a,'tcx> Builder<'a,'tcx> {
315324

316325
// otherwise, extract the next match pair and construct tests
317326
let match_pair = &candidates.last().unwrap().match_pairs[0];
318-
let test = self.test(match_pair);
327+
let mut test = self.test(match_pair);
328+
329+
// most of the time, the test to perform is simply a function
330+
// of the main candidate; but for a test like SwitchInt, we
331+
// may want to add cases based on the candidates that are
332+
// available
333+
match test.kind {
334+
TestKind::SwitchInt { switch_ty, ref mut options, ref mut indices } => {
335+
for candidate in &candidates {
336+
self.add_cases_to_switch(&match_pair.lvalue,
337+
candidate,
338+
switch_ty,
339+
options,
340+
indices);
341+
}
342+
}
343+
_ => { }
344+
}
345+
319346
debug!("match_candidates: test={:?} match_pair={:?}", test, match_pair);
320347
let target_blocks = self.perform_test(block, &match_pair.lvalue, &test);
321348

322-
for (outcome, mut target_block) in target_blocks.into_iter().enumerate() {
349+
for (outcome, target_block) in target_blocks.into_iter().enumerate() {
323350
let applicable_candidates: Vec<Candidate<'tcx>> =
324351
candidates.iter()
325352
.filter_map(|candidate| {
326-
unpack!(target_block =
327-
self.candidate_under_assumption(target_block,
328-
&match_pair.lvalue,
329-
&test.kind,
330-
outcome,
331-
candidate))
353+
self.candidate_under_assumption(&match_pair.lvalue,
354+
&test.kind,
355+
outcome,
356+
candidate)
332357
})
333358
.collect();
334359
self.match_candidates(span, arm_blocks, applicable_candidates, target_block);

0 commit comments

Comments
 (0)