Tell LLVM when a match is exhaustive
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:
```
This commit is contained in:
parent
5ca60d9431
commit
91f7c60d2d
2 changed files with 35 additions and 1 deletions
|
|
@ -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
|
||||
|
|
@ -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),
|
||||
|
|
|
|||
30
src/test/codegen/match.rs
Normal file
30
src/test/codegen/match.rs
Normal file
|
|
@ -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 => (),
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue