Skip to content

Commit dde7283

Browse files
committed
Auto merge of #28651 - dotdash:exhaustive_match, r=eddyb
By putting an "unreachable" instruction into the default arm of a switch instruction we can let LLVM know that the match is exhaustive, allowing for better optimizations. For example, this match: ```rust pub enum Enum { One, Two, Three, } impl Enum { pub fn get_disc(self) -> u8 { match self { Enum::One => 0, Enum::Two => 1, Enum::Three => 2, } } } ``` Currently compiles to this on x86_64: ```asm .cfi_startproc movzbl %dil, %ecx cmpl $1, %ecx setne %al testb %cl, %cl je .LBB0_2 incb %al movb %al, %dil .LBB0_2: movb %dil, %al retq .Lfunc_end0: ``` But with this change we get: ```asm .cfi_startproc movb %dil, %al retq .Lfunc_end0: ```
2 parents 90c04d0 + 91f7c60 commit dde7283

File tree

2 files changed

+35
-1
lines changed

2 files changed

+35
-1
lines changed

src/librustc_trans/trans/_match.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1283,6 +1283,10 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
12831283
let exhaustive = chk.is_infallible() && defaults.is_empty();
12841284
let len = opts.len();
12851285

1286+
if exhaustive && kind == Switch {
1287+
build::Unreachable(else_cx);
1288+
}
1289+
12861290
// Compile subtrees for each option
12871291
for (i, opt) in opts.iter().enumerate() {
12881292
// In some cases of range and vector pattern matching, we need to
@@ -1293,7 +1297,7 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
12931297
let mut opt_cx = else_cx;
12941298
let debug_loc = opt.debug_loc();
12951299

1296-
if !exhaustive || i + 1 < len {
1300+
if kind == Switch || !exhaustive || i + 1 < len {
12971301
opt_cx = bcx.fcx.new_temp_block("match_case");
12981302
match kind {
12991303
Single => Br(bcx, opt_cx.llbb, debug_loc),

src/test/codegen/match.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2015 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+
// compile-flags: -C no-prepopulate-passes
12+
13+
#![crate_type = "lib"]
14+
15+
pub enum E {
16+
A,
17+
B,
18+
}
19+
20+
// CHECK-LABEL: @exhaustive_match
21+
#[no_mangle]
22+
pub fn exhaustive_match(e: E) {
23+
// CHECK: switch{{.*}}, label %[[DEFAULT:[a-zA-Z0-9_]+]]
24+
// CHECK: [[DEFAULT]]:
25+
// CHECK-NEXT: unreachable
26+
match e {
27+
E::A => (),
28+
E::B => (),
29+
}
30+
}

0 commit comments

Comments
 (0)