Skip to content

Commit 935dc8d

Browse files
committed
Make SwitchInt switch on Operand
We can easily translate a SwitchInt with a Constant Operand, and it also helps us to constant propagate the thing.
1 parent 1b3e945 commit 935dc8d

File tree

10 files changed

+293
-22
lines changed

10 files changed

+293
-22
lines changed

src/librustc/mir/repr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ pub enum TerminatorKind<'tcx> {
395395
/// to one of the targets, and otherwise fallback to `otherwise`
396396
SwitchInt {
397397
/// discriminant value being tested
398-
discr: Lvalue<'tcx>,
398+
discr: Operand<'tcx>,
399399

400400
/// type of value being tested
401401
switch_ty: Ty<'tcx>,

src/librustc/mir/visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ macro_rules! make_mir_visitor {
378378
ref $($mutability)* switch_ty,
379379
ref $($mutability)* values,
380380
ref targets } => {
381-
self.visit_lvalue(discr, LvalueContext::Inspect);
381+
self.visit_operand(discr);
382382
self.visit_ty(switch_ty);
383383
for value in values {
384384
self.visit_const_val(value);

src/librustc_borrowck/borrowck/mir/gather_moves.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -660,13 +660,12 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
660660
}
661661
}
662662

663-
TerminatorKind::SwitchInt { switch_ty: _, values: _, targets: _, ref discr } |
664-
TerminatorKind::Switch { adt_def: _, targets: _, ref discr } => {
663+
TerminatorKind::SwitchInt { switch_ty: _, values: _, targets: _, discr: _ } |
664+
TerminatorKind::Switch { adt_def: _, targets: _, discr: _ } => {
665665
// The `discr` is not consumed; that is instead
666666
// encoded on specific match arms (and for
667667
// SwitchInt`, it is always a copyable integer
668668
// type anyway).
669-
let _ = discr;
670669
}
671670

672671
TerminatorKind::Drop { ref location, target: _, unwind: _ } => {

src/librustc_mir/build/matches/test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
238238

239239
(targets.clone(),
240240
TerminatorKind::SwitchInt {
241-
discr: lvalue.clone(),
241+
discr: Operand::Consume(lvalue.clone()),
242242
switch_ty: switch_ty,
243243
values: options.clone(),
244244
targets: targets

src/librustc_mir/transform/const_propagate.rs

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -228,10 +228,12 @@ impl<'a, 'tcx> Transfer<'tcx> for ConstTransfer<'a, 'tcx> {
228228
lat.insert(lval, bool_const(true));
229229
vec![lat, falsy]
230230
}
231-
TerminatorKind::SwitchInt { ref discr, ref values, switch_ty, .. } => {
231+
TerminatorKind::SwitchInt { discr: Operand::Consume(ref lval),
232+
ref values,
233+
switch_ty, .. } => {
232234
let mut vec: Vec<_> = values.iter().map(|val| {
233235
let mut branch = lat.clone();
234-
branch.insert(discr, Constant {
236+
branch.insert(lval, Constant {
235237
span: span,
236238
ty: switch_ty,
237239
literal: Literal::Value { value: val.clone() }
@@ -283,9 +285,11 @@ impl<'a, 'tcx> Transfer<'tcx> for ConstTransfer<'a, 'tcx> {
283285
vec![lat; succ_count]
284286
}
285287
}
288+
// (unreachable if interleaved with simplify branches pass):
289+
TerminatorKind::SwitchInt { .. } | // The condition is constant
290+
TerminatorKind::If { .. } | // The condition is constant
291+
286292
TerminatorKind::Switch { .. } | // Might make some sense to handle this
287-
TerminatorKind::If { .. } | // The condition is constant
288-
// (unreachable if interleaved with simplify branches pass)
289293
TerminatorKind::Goto { .. } |
290294
TerminatorKind::Unreachable |
291295
TerminatorKind::Return |
@@ -402,9 +406,7 @@ impl<'tcx, T: Transfer<'tcx>> Rewrite<'tcx, T> for SimplifyRewrite {
402406
TerminatorChange::Terminator(nt)
403407
}
404408
TerminatorKind::If { ref targets, cond: Operand::Constant(Constant {
405-
literal: Literal::Value {
406-
value: ConstVal::Bool(cond)
407-
}, ..
409+
literal: Literal::Value { value: ConstVal::Bool(cond) }, ..
408410
}) } => {
409411
let mut nt = t.clone();
410412
if cond {
@@ -414,11 +416,32 @@ impl<'tcx, T: Transfer<'tcx>> Rewrite<'tcx, T> for SimplifyRewrite {
414416
}
415417
TerminatorChange::Terminator(nt)
416418
}
419+
417420
TerminatorKind::SwitchInt { ref targets, .. } if targets.len() == 1 => {
418-
let mut nt = t.clone();
419-
nt.kind = TerminatorKind::Goto { target: targets[0] };
420-
TerminatorChange::Terminator(nt)
421+
TerminatorChange::Terminator(Terminator {
422+
source_info: t.source_info,
423+
kind: TerminatorKind::Goto { target: targets[0] }
424+
})
421425
}
426+
TerminatorKind::SwitchInt { discr: Operand::Constant(Constant {
427+
literal: Literal::Value { value: ref switch }, ..
428+
}), ref targets, ref values, .. } => {
429+
for (target, value) in targets.iter().zip(values.iter()) {
430+
if value == switch {
431+
return TerminatorChange::Terminator(Terminator {
432+
source_info: t.source_info,
433+
kind: TerminatorKind::Goto { target: *target }
434+
});
435+
}
436+
}
437+
TerminatorChange::Terminator(Terminator {
438+
source_info: t.source_info,
439+
kind: TerminatorKind::Goto {
440+
target: *targets.last().expect("SwitchInt has the `otherwise` target")
441+
}
442+
})
443+
}
444+
422445
TerminatorKind::Assert { target, cond: Operand::Constant(Constant {
423446
literal: Literal::Value {
424447
value: ConstVal::Bool(cond)
@@ -427,9 +450,10 @@ impl<'tcx, T: Transfer<'tcx>> Rewrite<'tcx, T> for SimplifyRewrite {
427450
// FIXME: once replacements with arbitrary subgraphs get implemented, this should
428451
// have success branch pointed to a block with Unreachable terminator when cond !=
429452
// expected.
430-
let mut nt = t.clone();
431-
nt.kind = TerminatorKind::Goto { target: target };
432-
TerminatorChange::Terminator(nt)
453+
TerminatorChange::Terminator(Terminator {
454+
source_info: t.source_info,
455+
kind: TerminatorKind::Goto { target: target }
456+
})
433457
}
434458
_ => TerminatorChange::Terminator(t.clone())
435459
}

src/librustc_mir/transform/type_check.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
423423
}
424424
}
425425
TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
426-
let discr_ty = discr.ty(mir, tcx).to_ty(tcx);
426+
let discr_ty = discr.ty(mir, tcx);
427427
if let Err(terr) = self.sub_types(self.last_span, discr_ty, switch_ty) {
428428
span_mirbug!(self, term, "bad SwitchInt ({:?} on {:?}): {:?}",
429429
switch_ty, discr_ty, terr);

src/librustc_trans/mir/block.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
175175

176176
mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => {
177177
let (otherwise, targets) = targets.split_last().unwrap();
178-
let discr = bcx.load(self.trans_lvalue(&bcx, discr).llval);
179-
let discr = bcx.with_block(|bcx| base::to_immediate(bcx, discr, switch_ty));
178+
let discr = self.trans_operand(&bcx, discr).immediate();
180179
let switch = bcx.switch(discr, llblock(self, *otherwise), values.len());
181180
for (value, target) in values.iter().zip(targets) {
182181
let val = Const::from_constval(bcx.ccx(), value.clone(), switch_ty);

src/test/mir-opt/const-prop-3.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
fn main() {
11+
let x = 0;
12+
match x {
13+
y@0 => ::std::process::exit(y),
14+
y@1 => ::std::process::exit(y),
15+
y@2 => ::std::process::exit(y),
16+
y@3 => ::std::process::exit(y),
17+
y@_ => ::std::process::exit(y),
18+
}
19+
}
20+
// END RUST SOURCE
21+
// START rustc.node4.ConstPropagate.before.mir
22+
// bb0: {
23+
// StorageLive(var0);
24+
// var0 = const 0i32;
25+
// switchInt(var0) -> [0i32: bb2, 1i32: bb3, 2i32: bb4, 3i32: bb5, otherwise: bb1];
26+
// }
27+
//
28+
// bb1: {
29+
// StorageLive(var5);
30+
// var5 = var0;
31+
// StorageLive(tmp4);
32+
// tmp4 = var5;
33+
// std::process::exit(tmp4);
34+
// }
35+
//
36+
// bb2: {
37+
// StorageLive(var1);
38+
// var1 = var0;
39+
// StorageLive(tmp0);
40+
// tmp0 = var1;
41+
// std::process::exit(tmp0);
42+
// }
43+
//
44+
// bb3: {
45+
// StorageLive(var2);
46+
// var2 = var0;
47+
// StorageLive(tmp1);
48+
// tmp1 = var2;
49+
// std::process::exit(tmp1);
50+
// }
51+
//
52+
// bb4: {
53+
// StorageLive(var3);
54+
// var3 = var0;
55+
// StorageLive(tmp2);
56+
// tmp2 = var3;
57+
// std::process::exit(tmp2);
58+
// }
59+
//
60+
// bb5: {
61+
// StorageLive(var4);
62+
// var4 = var0;
63+
// StorageLive(tmp3);
64+
// tmp3 = var4;
65+
// std::process::exit(tmp3);
66+
// }
67+
// END rustc.node4.ConstPropagate.before.mir
68+
// START rustc.node4.DeadCode.after.mir
69+
// bb0: {
70+
// StorageLive(var0);
71+
// goto -> bb1;
72+
// }
73+
//
74+
// bb1: {
75+
// StorageLive(var1);
76+
// StorageLive(tmp0);
77+
// std::process::exit(const 0i32);
78+
// }
79+
// END rustc.node4.DeadCode.after.mir

src/test/mir-opt/const-prop-loop-2.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main(){
12+
let mut x = 0;
13+
let mut y = true;
14+
while y {
15+
if x != 0 {
16+
x = 1;
17+
}
18+
y = false;
19+
}
20+
println(x);
21+
}
22+
23+
fn println(x: u32) {
24+
println!("{}", x);
25+
}
26+
// END RUST SOURCE
27+
// START rustc.node4.ConstPropagate.before.mir
28+
// bb0: {
29+
// var0 = const 0u32;
30+
// var1 = const true;
31+
// goto -> bb1;
32+
// }
33+
//
34+
// bb1: {
35+
// tmp1 = var1;
36+
// if(tmp1) -> [true: bb3, false: bb2];
37+
// }
38+
//
39+
// bb2: {
40+
// tmp0 = ();
41+
// tmp7 = var0;
42+
// tmp6 = println(tmp7) -> bb7;
43+
// }
44+
//
45+
// bb3: {
46+
// tmp5 = var0;
47+
// tmp4 = Ne(tmp5, const 0u32);
48+
// if(tmp4) -> [true: bb4, false: bb5];
49+
// }
50+
//
51+
// bb4: {
52+
// var0 = const 1u32;
53+
// tmp3 = ();
54+
// goto -> bb6;
55+
// }
56+
//
57+
// bb5: {
58+
// tmp3 = ();
59+
// goto -> bb6;
60+
// }
61+
//
62+
// bb6: {
63+
// var1 = const false;
64+
// tmp2 = ();
65+
// goto -> bb1;
66+
// }
67+
// END rustc.node4.ConstPropagate.before.mir
68+
// START rustc.node4.DeadCode.after.mir
69+
// bb0: {
70+
// var1 = const true;
71+
// goto -> bb1;
72+
// }
73+
//
74+
// bb1: {
75+
// tmp1 = var1;
76+
// if(tmp1) -> [true: bb3, false: bb2];
77+
// }
78+
//
79+
// bb2: {
80+
// tmp6 = println(const 0u32) -> bb4;
81+
// }
82+
//
83+
// bb3: {
84+
// var1 = const false;
85+
// goto -> bb1;
86+
// }
87+
// END rustc.node4.DeadCode.after.mir

0 commit comments

Comments
 (0)