Skip to content

Commit

Permalink
Auto merge of #28651 - dotdash:exhaustive_match, r=eddyb
Browse files Browse the repository at this point in the history
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:
```
  • Loading branch information
bors committed Sep 27, 2015
2 parents 90c04d0 + 91f7c60 commit dde7283
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 1 deletion.
6 changes: 5 additions & 1 deletion src/librustc_trans/trans/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1283,6 +1283,10 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
let exhaustive = chk.is_infallible() && defaults.is_empty();
let len = opts.len();

if exhaustive && kind == Switch {
build::Unreachable(else_cx);
}

// Compile subtrees for each option
for (i, opt) in opts.iter().enumerate() {
// In some cases of range and vector pattern matching, we need to
Expand All @@ -1293,7 +1297,7 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
let mut opt_cx = else_cx;
let debug_loc = opt.debug_loc();

if !exhaustive || i + 1 < len {
if kind == Switch || !exhaustive || i + 1 < len {
opt_cx = bcx.fcx.new_temp_block("match_case");
match kind {
Single => Br(bcx, opt_cx.llbb, debug_loc),
Expand Down
30 changes: 30 additions & 0 deletions src/test/codegen/match.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-flags: -C no-prepopulate-passes

#![crate_type = "lib"]

pub enum E {
A,
B,
}

// CHECK-LABEL: @exhaustive_match
#[no_mangle]
pub fn exhaustive_match(e: E) {
// CHECK: switch{{.*}}, label %[[DEFAULT:[a-zA-Z0-9_]+]]
// CHECK: [[DEFAULT]]:
// CHECK-NEXT: unreachable
match e {
E::A => (),
E::B => (),
}
}

0 comments on commit dde7283

Please sign in to comment.