forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of rust-lang#87794 - bonega:enum_niche_prefer_zero, r=nagisa
Enum should prefer discriminant zero for niche Given an enum with unassigned zero-discriminant, rust should prefer it for niche selection. Zero as discriminant for `Option<Enum>` makes it possible for LLVM to optimize resulting asm. - Eliminate branch when expected value coincides. - Use smaller instruction `test eax, eax` instead of `cmp eax, ?` - Possible interaction with zeroed memory? Example: ```rust pub enum Size { One = 1, Two = 2, Three = 3, } pub fn handle(x: Option<Size>) -> u8 { match x { None => {0} Some(size) => {size as u8} } } ``` In this case discriminant zero is available as a niche. Above example on nightly: ```asm mov eax, edi cmp al, 4 jne .LBB0_2 xor eax, eax .LBB0_2: ret ``` PR: ```asm mov eax, edi ret ``` I created this PR because I had a performance regression when I tried to use an enum to represent legal grapheme byte-length for utf8. Using an enum instead of `NonZeroU8` [here](https://github.com/bonega/yore/blob/d683304f5dfe2e99f769e6ab8adf8d60a0d1d9b3/src/internal/decoder_incomplete.rs#L90) resulted in a performance regression of about 5%. I consider this to be a somewhat realistic benchmark. Thanks to `@ogoffart` for pointing me in the right direction! Edit: Updated description
- Loading branch information
Showing
3 changed files
with
82 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// Check that niche selection prefers zero and that jumps are optimized away. | ||
// See https://github.com/rust-lang/rust/pull/87794 | ||
// assembly-output: emit-asm | ||
// only-x86 | ||
// compile-flags: -Copt-level=3 | ||
|
||
#![crate_type = "lib"] | ||
|
||
#[repr(u8)] | ||
pub enum Size { | ||
One = 1, | ||
Two = 2, | ||
Three = 3, | ||
} | ||
|
||
#[no_mangle] | ||
pub fn handle(x: Option<Size>) -> u8 { | ||
match x { | ||
None => 0, | ||
Some(size) => size as u8, | ||
} | ||
} | ||
|
||
// There should be no jumps in output | ||
// CHECK-NOT: j |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// Check that niche selection prefers zero. | ||
// See https://github.com/rust-lang/rust/pull/87794 | ||
// run-pass | ||
#[repr(u8)] | ||
pub enum Size { | ||
One = 1, | ||
Two = 2, | ||
Three = 3, | ||
} | ||
|
||
fn main() { | ||
// check that `None` is zero | ||
assert_eq!(0, unsafe { std::mem::transmute::<Option<Size>, u8>(None) }); | ||
} |