Skip to content

Commit 12d1653

Browse files
committed
Auto merge of #33583 - luqmana:tri-bool-mir, r=arielb1
MIR: Don't generate 3-armed boolean switch from match. Fixes #33540. Snippet from issue: ```Rust fn foo(x: bool, y: bool) -> u32 { match (x, y) { (false, _) => 0, (_, false) => 1, (true, true) => 2, } } ``` Generated MIR: ``` fn foo(arg0: bool, arg1: bool) -> u32 { let var0: bool; // "x" in scope 1 at 3bbm.rs:17:8: 17:9 let var1: bool; // "y" in scope 1 at 3bbm.rs:17:17: 17:18 let mut tmp0: (bool, bool); let mut tmp1: bool; let mut tmp2: bool; let mut tmp3: (&'static str, &'static str, u32); let mut tmp4: &'static (&'static str, &'static str, u32); bb0: { var0 = arg0; // scope 1 at 3bbm.rs:17:8: 17:9 var1 = arg1; // scope 1 at 3bbm.rs:17:17: 17:18 tmp1 = var0; // scope 5 at 3bbm.rs:18:12: 18:13 tmp2 = var1; // scope 6 at 3bbm.rs:18:15: 18:16 tmp0 = (tmp1, tmp2); // scope 4 at 3bbm.rs:18:11: 18:17 if((tmp0.0: bool)) -> [true: bb4, false: bb1]; // scope 3 at 3bbm.rs:19:10: 19:15 } bb1: { return = const 0u32; // scope 10 at 3bbm.rs:19:23: 19:24 goto -> bb7; // scope 3 at 3bbm.rs:18:5: 22:6 } bb2: { return = const 1u32; // scope 11 at 3bbm.rs:20:23: 20:24 goto -> bb7; // scope 3 at 3bbm.rs:18:5: 22:6 } bb3: { return = const 2u32; // scope 12 at 3bbm.rs:21:25: 21:26 goto -> bb7; // scope 3 at 3bbm.rs:18:5: 22:6 } bb4: { if((tmp0.1: bool)) -> [true: bb5, false: bb2]; // scope 3 at 3bbm.rs:20:13: 20:18 } bb5: { if((tmp0.0: bool)) -> [true: bb3, false: bb6]; // scope 3 at 3bbm.rs:21:10: 21:14 } bb6: { tmp4 = promoted0; // scope 3 at 3bbm.rs:18:5: 22:6 core::panicking::panic(tmp4); // scope 3 at 3bbm.rs:18:5: 22:6 } bb7: { return; // scope 0 at 3bbm.rs:17:1: 23:2 } } ``` Not sure about this approach. I was also thinking maybe just a standalone pass? cc @arielb1, @nagisa
2 parents b47a442 + a97f6b3 commit 12d1653

File tree

2 files changed

+78
-12
lines changed

2 files changed

+78
-12
lines changed

src/librustc_mir/build/matches/test.rs

+44-12
Original file line numberDiff line numberDiff line change
@@ -162,21 +162,53 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
162162
}
163163

164164
TestKind::SwitchInt { switch_ty, ref options, indices: _ } => {
165-
let otherwise = self.cfg.start_new_block();
166-
let targets: Vec<_> =
167-
options.iter()
168-
.map(|_| self.cfg.start_new_block())
169-
.chain(Some(otherwise))
170-
.collect();
165+
let (targets, term) = match switch_ty.sty {
166+
// If we're matching on boolean we can
167+
// use the If TerminatorKind instead
168+
ty::TyBool => {
169+
assert!(options.len() > 0 && options.len() <= 2);
170+
171+
let (true_bb, else_bb) =
172+
(self.cfg.start_new_block(),
173+
self.cfg.start_new_block());
174+
175+
let targets = match &options[0] {
176+
&ConstVal::Bool(true) => vec![true_bb, else_bb],
177+
&ConstVal::Bool(false) => vec![else_bb, true_bb],
178+
v => span_bug!(test.span, "expected boolean value but got {:?}", v)
179+
};
180+
181+
(targets,
182+
TerminatorKind::If {
183+
cond: Operand::Consume(lvalue.clone()),
184+
targets: (true_bb, else_bb)
185+
})
186+
187+
}
188+
_ => {
189+
// The switch may be inexhaustive so we
190+
// add a catch all block
191+
let otherwise = self.cfg.start_new_block();
192+
let targets: Vec<_> =
193+
options.iter()
194+
.map(|_| self.cfg.start_new_block())
195+
.chain(Some(otherwise))
196+
.collect();
197+
198+
(targets.clone(),
199+
TerminatorKind::SwitchInt {
200+
discr: lvalue.clone(),
201+
switch_ty: switch_ty,
202+
values: options.clone(),
203+
targets: targets
204+
})
205+
}
206+
};
207+
171208
self.cfg.terminate(block,
172209
scope_id,
173210
test.span,
174-
TerminatorKind::SwitchInt {
175-
discr: lvalue.clone(),
176-
switch_ty: switch_ty,
177-
values: options.clone(),
178-
targets: targets.clone(),
179-
});
211+
term);
180212
targets
181213
}
182214

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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+
// Issue #33540
12+
// We previously used to generate a 3-armed boolean `SwitchInt` in the
13+
// MIR of the function `foo` below. #33583 changed rustc to
14+
// generate an `If` terminator instead. This test is to just ensure
15+
// sanity in that we generate an if-else chain giving the correct
16+
// results.
17+
18+
#![feature(rustc_attrs)]
19+
20+
#[rustc_mir]
21+
fn foo(x: bool, y: bool) -> u32 {
22+
match (x, y) {
23+
(false, _) => 0,
24+
(_, false) => 1,
25+
(true, true) => 2
26+
}
27+
}
28+
29+
fn main() {
30+
assert_eq!(foo(false, true), 0);
31+
assert_eq!(foo(false, false), 0);
32+
assert_eq!(foo(true, false), 1);
33+
assert_eq!(foo(true, true), 2);
34+
}

0 commit comments

Comments
 (0)