Skip to content

Commit 94e587e

Browse files
committed
Only SwitchInt over integers, not all consts
Also use a Cow to avoid full Vec for all SwitchInts
1 parent 1355a57 commit 94e587e

File tree

10 files changed

+154
-101
lines changed

10 files changed

+154
-101
lines changed

src/librustc/middle/const_val.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@
1111
use syntax::symbol::InternedString;
1212
use syntax::ast;
1313
use std::rc::Rc;
14+
use std::borrow::Cow;
1415
use hir::def_id::DefId;
1516
use rustc_const_math::*;
1617
use self::ConstVal::*;
1718
pub use rustc_const_math::ConstInt;
1819

1920
use std::collections::BTreeMap;
2021

22+
pub static BOOL_SWITCH_TRUE: Cow<'static, [ConstInt]> = Cow::Borrowed(&[ConstInt::Infer(1)]);
23+
2124
#[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
2225
pub enum ConstVal {
2326
Float(ConstFloat),
@@ -49,4 +52,14 @@ impl ConstVal {
4952
Char(..) => "char",
5053
}
5154
}
55+
56+
pub fn to_const_int(&self) -> Option<ConstInt> {
57+
match *self {
58+
ConstVal::Integral(i) => Some(i),
59+
ConstVal::Bool(true) => Some(ConstInt::Infer(1)),
60+
ConstVal::Bool(false) => Some(ConstInt::Infer(0)),
61+
ConstVal::Char(ch) => Some(ConstInt::U32(ch as u32)),
62+
_ => None
63+
}
64+
}
5265
}

src/librustc/mir/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,9 @@ pub struct Terminator<'tcx> {
446446
pub kind: TerminatorKind<'tcx>
447447
}
448448

449+
/// For use in SwitchInt, for switching on bools.
450+
pub static BOOL_SWITCH_TRUE: Cow<'static, [ConstInt]> = Cow::Borrowed(&[ConstInt::Infer(1)]);
451+
449452
#[derive(Clone, RustcEncodable, RustcDecodable)]
450453
pub enum TerminatorKind<'tcx> {
451454
/// block should have one successor in the graph; we jump there
@@ -464,8 +467,7 @@ pub enum TerminatorKind<'tcx> {
464467

465468
/// Possible values. The locations to branch to in each case
466469
/// are found in the corresponding indices from the `targets` vector.
467-
// FIXME: ConstVal doesn’t quite make any sense here? Its a Switch*Int*.
468-
values: Vec<ConstVal>,
470+
values: Cow<'tcx, [ConstInt]>,
469471

470472
/// Possible branch sites. The length of this vector should be
471473
/// equal to the length of the `values` vector plus 1 -- the
@@ -696,7 +698,7 @@ impl<'tcx> TerminatorKind<'tcx> {
696698
values.iter()
697699
.map(|const_val| {
698700
let mut buf = String::new();
699-
fmt_const_val(&mut buf, const_val).unwrap();
701+
fmt_const_val(&mut buf, &ConstVal::Integral(*const_val)).unwrap();
700702
buf.into()
701703
})
702704
.chain(iter::once(String::from("otherwise").into()))

src/librustc/mir/visit.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,12 @@ macro_rules! make_mir_visitor {
223223
self.super_const_val(const_val);
224224
}
225225

226+
fn visit_const_int(&mut self,
227+
const_int: &ConstInt,
228+
_: Location) {
229+
self.super_const_int(const_int);
230+
}
231+
226232
fn visit_const_usize(&mut self,
227233
const_usize: & $($mutability)* ConstUsize,
228234
_: Location) {
@@ -364,12 +370,12 @@ macro_rules! make_mir_visitor {
364370

365371
TerminatorKind::SwitchInt { ref $($mutability)* discr,
366372
ref $($mutability)* switch_ty,
367-
ref $($mutability)* values,
373+
ref values,
368374
ref targets } => {
369375
self.visit_operand(discr, source_location);
370376
self.visit_ty(switch_ty);
371-
for value in values {
372-
self.visit_const_val(value, source_location);
377+
for value in &values[..] {
378+
self.visit_const_int(value, source_location);
373379
}
374380
for &target in targets {
375381
self.visit_branch(block, target);
@@ -698,10 +704,13 @@ macro_rules! make_mir_visitor {
698704
_substs: & $($mutability)* ClosureSubsts<'tcx>) {
699705
}
700706

701-
fn super_const_val(&mut self, _substs: & $($mutability)* ConstVal) {
707+
fn super_const_val(&mut self, _const_val: & $($mutability)* ConstVal) {
708+
}
709+
710+
fn super_const_int(&mut self, _const_int: &ConstInt) {
702711
}
703712

704-
fn super_const_usize(&mut self, _substs: & $($mutability)* ConstUsize) {
713+
fn super_const_usize(&mut self, _const_usize: & $($mutability)* ConstUsize) {
705714
}
706715

707716
// Convenience methods

src/librustc_borrowck/borrowck/mir/elaborate_drops.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
679679
let discr = ConstInt::new_inttype(variant.disr_val, adt.discr_ty,
680680
self.tcx.sess.target.uint_type,
681681
self.tcx.sess.target.int_type).unwrap();
682-
values.push(ConstVal::Integral(discr));
682+
values.push(discr);
683683
blocks.push(self.open_drop_for_variant(c, &mut drop_block, adt, substs, idx));
684684
}
685685
// If there are multiple variants, then if something
@@ -704,7 +704,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
704704
kind: TerminatorKind::SwitchInt {
705705
discr: Operand::Consume(discr),
706706
switch_ty: discr_ty,
707-
values: values,
707+
values: From::from(values),
708708
targets: blocks,
709709
// adt_def: adt,
710710
// targets: variant_drops
@@ -836,7 +836,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
836836
self.new_block(c, is_cleanup, TerminatorKind::SwitchInt {
837837
discr: Operand::Consume(flag),
838838
switch_ty: boolty,
839-
values: vec![ConstVal::Bool(true)],
839+
values: BOOL_SWITCH_TRUE.clone(),
840840
targets: vec![on_set, on_unset],
841841
})
842842
}

src/librustc_mir/build/expr/into.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use build::expr::category::{Category, RvalueFunc};
1515
use hair::*;
1616
use rustc::ty;
1717
use rustc::mir::*;
18-
use rustc::middle::const_val::ConstVal;
1918

2019
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
2120
/// Compile `expr`, storing the result into `destination`, which
@@ -73,7 +72,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
7372
this.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
7473
discr: operand,
7574
switch_ty: this.hir.bool_ty(),
76-
values: vec![ConstVal::Bool(true)],
75+
values: BOOL_SWITCH_TRUE.clone(),
7776
targets: vec![then_block, else_block],
7877
});
7978

@@ -120,15 +119,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
120119
this.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
121120
discr: lhs,
122121
switch_ty: this.hir.bool_ty(),
123-
values: vec![ConstVal::Bool(true)],
122+
values: BOOL_SWITCH_TRUE.clone(),
124123
targets: blocks,
125124
});
126125

127126
let rhs = unpack!(else_block = this.as_operand(else_block, rhs));
128127
this.cfg.terminate(else_block, source_info, TerminatorKind::SwitchInt {
129128
discr: rhs,
130129
switch_ty: this.hir.bool_ty(),
131-
values: vec![ConstVal::Bool(true)],
130+
values: BOOL_SWITCH_TRUE.clone(),
132131
targets: vec![true_block, false_block],
133132
});
134133

@@ -192,7 +191,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
192191
TerminatorKind::SwitchInt {
193192
discr: cond,
194193
switch_ty: this.hir.bool_ty(),
195-
values: vec![ConstVal::Bool(true)],
194+
values: BOOL_SWITCH_TRUE.clone(),
196195
targets: vec![body_block, exit_block],
197196
});
198197

src/librustc_mir/build/matches/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -675,7 +675,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
675675
self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
676676
discr: cond,
677677
switch_ty: self.hir.bool_ty(),
678-
values: vec![ConstVal::Bool(true)],
678+
values: BOOL_SWITCH_TRUE.clone(),
679679
targets: vec![arm_block, otherwise],
680680
});
681681
Some(otherwise)

src/librustc_mir/build/matches/test.rs

Lines changed: 39 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
196196
let discr = ConstInt::new_inttype(variant.disr_val, adt_def.discr_ty,
197197
tcx.sess.target.uint_type,
198198
tcx.sess.target.int_type).unwrap();
199-
values.push(ConstVal::Integral(discr));
199+
values.push(discr);
200200
*(targets.place_back() <- self.cfg.start_new_block())
201201
} else {
202202
if otherwise_block.is_none() {
@@ -226,59 +226,45 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
226226
self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
227227
discr: Operand::Consume(discr),
228228
switch_ty: discr_ty,
229-
values: values,
229+
values: From::from(values),
230230
targets: targets
231231
});
232232
target_blocks
233233
}
234234

235235
TestKind::SwitchInt { switch_ty, ref options, indices: _ } => {
236-
let (targets, term) = match switch_ty.sty {
237-
// If we're matching on boolean we can
238-
// use the If TerminatorKind instead
239-
ty::TyBool => {
240-
assert!(options.len() > 0 && options.len() <= 2);
241-
242-
let (true_bb, else_bb) =
243-
(self.cfg.start_new_block(),
244-
self.cfg.start_new_block());
245-
246-
let targets = match &options[0] {
247-
&ConstVal::Bool(true) => vec![true_bb, else_bb],
248-
&ConstVal::Bool(false) => vec![else_bb, true_bb],
249-
v => span_bug!(test.span, "expected boolean value but got {:?}", v)
250-
};
251-
252-
(targets, TerminatorKind::SwitchInt {
253-
discr: Operand::Consume(lvalue.clone()),
254-
switch_ty: self.hir.bool_ty(),
255-
values: vec![ConstVal::Bool(true)],
256-
targets: vec![true_bb, else_bb]
257-
})
258-
259-
}
260-
_ => {
261-
// The switch may be inexhaustive so we
262-
// add a catch all block
263-
let otherwise = self.cfg.start_new_block();
264-
let targets: Vec<_> =
265-
options.iter()
266-
.map(|_| self.cfg.start_new_block())
267-
.chain(Some(otherwise))
268-
.collect();
269-
270-
(targets.clone(),
271-
TerminatorKind::SwitchInt {
272-
discr: Operand::Consume(lvalue.clone()),
273-
switch_ty: switch_ty,
274-
values: options.clone(),
275-
targets: targets
276-
})
277-
}
236+
let (values, targets, ret) = if switch_ty.sty == ty::TyBool {
237+
assert!(options.len() > 0 && options.len() <= 2);
238+
let (true_bb, false_bb) = (self.cfg.start_new_block(),
239+
self.cfg.start_new_block());
240+
let ret = match &options[0] {
241+
&ConstVal::Bool(true) => vec![true_bb, false_bb],
242+
&ConstVal::Bool(false) => vec![false_bb, true_bb],
243+
v => span_bug!(test.span, "expected boolean value but got {:?}", v)
244+
};
245+
(BOOL_SWITCH_TRUE.clone(), vec![true_bb, false_bb], ret)
246+
} else {
247+
// The switch may be inexhaustive so we
248+
// add a catch all block
249+
let otherwise = self.cfg.start_new_block();
250+
let targets: Vec<_> =
251+
options.iter()
252+
.map(|_| self.cfg.start_new_block())
253+
.chain(Some(otherwise))
254+
.collect();
255+
let values: Vec<_> = options.iter().map(|v|
256+
v.to_const_int().expect("switching on integral")
257+
).collect();
258+
(From::from(values), targets.clone(), targets)
278259
};
279260

280-
self.cfg.terminate(block, source_info, term);
281-
targets
261+
self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
262+
discr: Operand::Consume(lvalue.clone()),
263+
switch_ty: switch_ty,
264+
values: values,
265+
targets: targets.clone(),
266+
});
267+
ret
282268
}
283269

284270
TestKind::Eq { ref value, mut ty } => {
@@ -346,10 +332,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
346332
self.cfg.terminate(eq_block, source_info, TerminatorKind::SwitchInt {
347333
discr: Operand::Consume(eq_result),
348334
switch_ty: self.hir.bool_ty(),
349-
values: vec![ConstVal::Bool(true)],
335+
values: BOOL_SWITCH_TRUE.clone(),
350336
targets: vec![block, fail],
351337
});
352-
353338
vec![block, fail]
354339
} else {
355340
let block = self.compare(block, fail, test.span, BinOp::Eq, expect, val);
@@ -391,16 +376,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
391376
Operand::Consume(expected)));
392377

393378
// branch based on result
394-
let target_blocks: Vec<_> = vec![self.cfg.start_new_block(),
395-
self.cfg.start_new_block()];
379+
let (false_bb, true_bb) = (self.cfg.start_new_block(),
380+
self.cfg.start_new_block());
396381
self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
397382
discr: Operand::Consume(result),
398383
switch_ty: self.hir.bool_ty(),
399-
values: vec![ConstVal::Bool(true)],
400-
targets: target_blocks.clone(),
384+
values: BOOL_SWITCH_TRUE.clone(),
385+
targets: vec![true_bb, false_bb],
401386
});
402-
403-
target_blocks
387+
vec![true_bb, false_bb]
404388
}
405389
}
406390
}
@@ -425,10 +409,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
425409
self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
426410
discr: Operand::Consume(result),
427411
switch_ty: self.hir.bool_ty(),
428-
values: vec![ConstVal::Bool(true)],
412+
values: BOOL_SWITCH_TRUE.clone(),
429413
targets: vec![target_block, fail_block]
430414
});
431-
432415
target_block
433416
}
434417

src/librustc_trans/mir/block.rs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use llvm::{self, ValueRef, BasicBlockRef};
1212
use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err};
1313
use rustc::middle::lang_items;
14+
use rustc::middle::const_val::ConstInt;
1415
use rustc::ty::{self, layout};
1516
use rustc::mir;
1617
use abi::{Abi, FnType, ArgType};
@@ -134,14 +135,24 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
134135
}
135136

136137
mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => {
137-
// TODO: cond_br if only 1 value
138-
let (otherwise, targets) = targets.split_last().unwrap();
139-
let discr = self.trans_operand(&bcx, discr).immediate();
140-
let switch = bcx.switch(discr, llblock(self, *otherwise), values.len());
141-
for (value, target) in values.iter().zip(targets) {
142-
let val = Const::from_constval(bcx.ccx, value.clone(), switch_ty);
143-
let llbb = llblock(self, *target);
144-
bcx.add_case(switch, val.llval, llbb)
138+
let discr = self.trans_operand(&bcx, discr);
139+
if switch_ty == bcx.tcx().types.bool {
140+
let lltrue = llblock(self, targets[0]);
141+
let llfalse = llblock(self, targets[1]);
142+
if let [ConstInt::Infer(0)] = values[..] {
143+
bcx.cond_br(discr.immediate(), llfalse, lltrue);
144+
} else {
145+
bcx.cond_br(discr.immediate(), lltrue, llfalse);
146+
}
147+
} else {
148+
let (otherwise, targets) = targets.split_last().unwrap();
149+
let switch = bcx.switch(discr.immediate(),
150+
llblock(self, *otherwise), values.len());
151+
for (value, target) in values.iter().zip(targets) {
152+
let val = Const::from_constint(bcx.ccx, value);
153+
let llbb = llblock(self, *target);
154+
bcx.add_case(switch, val.llval, llbb)
155+
}
145156
}
146157
}
147158

0 commit comments

Comments
 (0)