# Why can't conversion to an enum be inlined?

**URL:** <https://internals.rust-lang.org/t/why-cant-conversion-to-an-enum-be-inlined/9490>\
**Category:** compiler\
**Created:** [February 21, 2019, 7:10am UTC](https://internals.rust-lang.org/t/why-cant-conversion-to-an-enum-be-inlined/9490 "2019-02-21T07:10:42Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ryan1729](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ryan1729/32/4770_2.png) [@Ryan1729](https://internals.rust-lang.org/u/Ryan1729)\
**Post date:** [February 21, 2019, 7:10am UTC](https://internals.rust-lang.org/t/why-cant-conversion-to-an-enum-be-inlined/9490/1 "2019-02-21T07:10:43Z")

</div>

This is entirely out of curiosity, but is there a reason why the in the following code `using_enum` produces more instructions than `using_u8`? I would have thought that the output would be identical.

[Godbolt link](https://godbolt.org/z/6X4KW5)

```rust
pub fn using_u8(n: u8) -> u8 {
    let row_type = n % 3;

    match row_type {
        0 => a(n),
        1 => b(n),
        _ => c(n),
    }
}

enum RowType {
    Left, Middle, Right
}

fn get_row_type(n: u8) -> RowType {
    let row_type = n % 3;

    match row_type {
        0 => RowType::Left,
        1 => RowType::Middle,
        _ => RowType::Right,
    }
}

pub fn using_enum(n: u8) -> u8 {
    match get_row_type(n) {
        RowType::Left => a(n),
        RowType::Middle => b(n),
        RowType::Right => c(n),
    }
}

#[inline(never)]
fn a(n: u8) -> u8 { n ^ 0b1010101 }
#[inline(never)]
fn b(n: u8) -> u8 { n ^ 0b1101 }
#[inline(never)]
fn c(n: u8) -> u8 { n ^ 0b10101 }

```

---

<div class="post-metadata">

**Author:** ![dhm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dhm/32/4879_2.png) [@dhm](https://internals.rust-lang.org/u/dhm)\
**Post date:** [February 21, 2019, 1:47pm UTC](https://internals.rust-lang.org/t/why-cant-conversion-to-an-enum-be-inlined/9490/2 "2019-02-21T13:47:55Z")

</div>

Both things aren't really comparable: the enum example performs 2 matches, whereas your u8 example does not.

I've made the following example, which is better reflects what the enum does (I've chosen to use `#[repr(u8)]` since I am using `u8` constants):

```rust
const LEFT : u8 = 0;
const MIDDLE : u8 = 1;
const RIGHT : u8 = 2;

pub fn get_row_type_u8(n: u8) -> u8 {
    let row_type = n % 3;

    match row_type {
        0 => LEFT,
        1 => MIDDLE,
        _ => RIGHT,
    }

}

#[repr(u8)]
enum RowType {
    Left, Middle, Right
}

fn get_row_type_enum(n: u8) -> RowType {
    let row_type = n % 3;

    match row_type {
        0 => RowType::Left,
        1 => RowType::Middle,
        _ => RowType::Right,
    }
}

#[no_mangle]
pub
fn using_enum(n: u8) -> u8 {
    match get_row_type_enum(n) {
        RowType::Left => a(n),
        RowType::Middle => b(n),
        RowType::Right => c(n),
    }
}

#[no_mangle]
pub
fn using_u8(n: u8) -> u8 {
    match get_row_type_u8(n) {
        LEFT => a(n),
        MIDDLE => b(n),
        RIGHT => c(n),
        _ => unsafe { std::hint::unreachable_unchecked() },
    }
}

#[inline(never)]
fn a(n: u8) -> u8 { n ^ 0b1010101 }
#[inline(never)]
fn b(n: u8) -> u8 { n ^ 0b1101 }
#[inline(never)]
fn c(n: u8) -> u8 { n ^ 0b10101 }

/// An #[inline(always)] std::hint::unreachable_unchecked()
mod std {
    pub mod hint {
        #[inline(always)]
        /// UB UB UB
        pub unsafe fn unreachable_unchecked () -> !
        {
            struct VoidStruct; enum VoidType {}
            match ::std::mem::transmute::<_, VoidType>(VoidStruct) {}
        }
    }
}

```

This then gives (Godbolt can't handle explicit unreachable hints)

 ![Screenshot%20from%202019-02-21%2014-46-34](https://us1.discourse-cdn.com/flex002/uploads/rustlang/original/2X/c/c434be0c8ae1377ae026fc3ae96bc69e7dd6f23b.png)They are outstandingly similar.

Which is confirmed when building in `--release` mode:

```rust
$ nm ./target/release/libtemp.so | grep using
0000000000000960 T using_enum
0000000000000960 T using_u8

```

Thus, the problem does not seem to come from using enums but from the 2 consecutive matches.

---

<div class="post-metadata">

**Author:** ![tspiteri](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tspiteri/32/7283_2.png) [@tspiteri](https://internals.rust-lang.org/u/tspiteri)\
**Post date:** [February 21, 2019, 3:20pm UTC](https://internals.rust-lang.org/t/why-cant-conversion-to-an-enum-be-inlined/9490/3 "2019-02-21T15:20:27Z")

</div>

It looks like a missed optimization somewhere. When I change the match statement in `get_row_type` to the below, `using_u8` and `using_enum` produce the exact same assembly such that it is unified into one function.

```rust
    match row_type {
        0 => RowType::Left,
        1 => RowType::Middle,
        2 => RowType::Right,
        _ => RowType::Right,
    }

```

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [May 22, 2019, 3:20pm UTC](https://internals.rust-lang.org/t/why-cant-conversion-to-an-enum-be-inlined/9490/4 "2019-05-22T15:20:31Z")

</div>

Closed on May 22, 2019, 3:20pm UTC

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
