Skip to content

Utilize discriminant_value for more efficient deriving #26280

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 17, 2015

Conversation

Marwes
Copy link
Contributor

@Marwes Marwes commented Jun 13, 2015

PR for #26128.

Improves codegen in deriving by utilizing the discriminant_value intrinsic.

I have a more detailed comment on the changes in a comment on the issue here

Old

running 7 tests
test large_c_like       ... bench:   2,694,129 ns/iter (+/- 5,170)
test large_c_like_ord   ... bench:   2,723,521 ns/iter (+/- 9,098)
test test1_partial_eq   ... bench:   2,439,317 ns/iter (+/- 2,135)
test test1_partial_ord  ... bench:   2,499,114 ns/iter (+/- 55,766)
test test2_partial_eq   ... bench:   3,562,815 ns/iter (+/- 45,590)
test test2_partial_ord  ... bench:   3,398,306 ns/iter (+/- 22,180)
test test_match_success ... bench:   1,509,267 ns/iter (+/- 1,982)

New

running 7 tests
test large_c_like       ... bench:     286,509 ns/iter (+/- 474)
test large_c_like_ord   ... bench:     286,666 ns/iter (+/- 8,756)
test test1_partial_eq   ... bench:     286,584 ns/iter (+/- 2,789)
test test1_partial_ord  ... bench:     286,470 ns/iter (+/- 516)
test test2_partial_eq   ... bench:   2,228,997 ns/iter (+/- 34,191)
test test2_partial_ord  ... bench:   1,731,699 ns/iter (+/- 21,756)
test test_match_success ... bench:   1,509,630 ns/iter (+[- 3,765)

Benchmark

The new code generated for deriving on enums looks something like this:

```rust
let __self0_vi = unsafe {
    std::intrinsics::discriminant_value(&self) } as i32;
let __self1_vi = unsafe {
    std::intrinsics::discriminant_value(&__arg1) } as i32;
let __self2_vi = unsafe {
    std::intrinsics::discriminant_value(&__arg2) } as i32;
///
if __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... {
    match (...) {
        (Variant1, Variant1, ...) => Body1
        (Variant2, Variant2, ...) => Body2,
        ...
        _ => ::core::intrinsics::unreachable()
    }
}
else {
    ... // catch-all remainder can inspect above variant index values.
}
```
This helps massively for C-like enums since they will be compiled as a
single comparison giving observed speedups of up to 8x. For more complex
enums the speedup is more difficult to measure but it should not be
slower to generate code this way regardless.
@rust-highfive
Copy link
Contributor

r? @alexcrichton

(rust_highfive has picked a reviewer for you, use r? to override)

@pcwalton
Copy link
Contributor

Do you know if this improves compile times of rustc?

@Marwes
Copy link
Contributor Author

Marwes commented Jun 13, 2015

@pcwalton I haven't tested the compile times so I can't say for certain. C-like enums generate a lot better IR which should help make both compiled programs faster as well as compiling that code faster. Other enums should get a less noticeable speedup as well.

I might do some benchmarking on the compiler tomorrow to see if it makes a difference though.

@@ -1048,15 +1048,23 @@ impl<'a> MethodDef<'a> {
/// discriminant values. See issue #15523.)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looks like this bug #15523 was fixed, so it's a good time to update this comment too I think. I assume using discr value is always correct now?

@bluss
Copy link
Member

bluss commented Jun 14, 2015

Does this affect codegen for Option<T>? Just thinking of our most important enum.

@Marwes
Copy link
Contributor Author

Marwes commented Jun 14, 2015

I ran the same benchmark on an Option and I got a 1.1x speedup. So I'd guess it helps a little though it might very well vary depending on what type the Option contains.

@bluss
Copy link
Member

bluss commented Jun 14, 2015

That's nice.

@Marwes
Copy link
Contributor Author

Marwes commented Jun 14, 2015

@pcwalton I compiled rustc a few times with and without this PR but I got to much noise to be able to say anything. Does not look like it makes a noticeable difference though.

EDIT: Meant to write that it does not look like it makes a noticeable difference.

Replaced it with a comment mentioning the rationale for checking the discriminants first.
@Marwes
Copy link
Contributor Author

Marwes commented Jun 14, 2015

Removed the comment mentioning #15523 as per @bluss suggestion, as that had been fixed.

@alexcrichton
Copy link
Member

r? @huonw, I think you're more familiar with this than I

@rust-highfive rust-highfive assigned huonw and unassigned alexcrichton Jun 15, 2015
@pcwalton
Copy link
Contributor

@bors: r+

@bors
Copy link
Collaborator

bors commented Jun 16, 2015

📌 Commit 34d5b54 has been approved by pcwalton

@bors
Copy link
Collaborator

bors commented Jun 16, 2015

⌛ Testing commit 34d5b54 with merge 014a5c1...

bors added a commit that referenced this pull request Jun 16, 2015
PR for #26128.

Improves codegen in deriving by utilizing the discriminant_value intrinsic.

I have a more detailed comment on the changes in a comment on the issue [here](#26128 (comment))

### Old
```
running 7 tests
test large_c_like       ... bench:   2,694,129 ns/iter (+/- 5,170)
test large_c_like_ord   ... bench:   2,723,521 ns/iter (+/- 9,098)
test test1_partial_eq   ... bench:   2,439,317 ns/iter (+/- 2,135)
test test1_partial_ord  ... bench:   2,499,114 ns/iter (+/- 55,766)
test test2_partial_eq   ... bench:   3,562,815 ns/iter (+/- 45,590)
test test2_partial_ord  ... bench:   3,398,306 ns/iter (+/- 22,180)
test test_match_success ... bench:   1,509,267 ns/iter (+/- 1,982)
```

### New
```
running 7 tests
test large_c_like       ... bench:     286,509 ns/iter (+/- 474)
test large_c_like_ord   ... bench:     286,666 ns/iter (+/- 8,756)
test test1_partial_eq   ... bench:     286,584 ns/iter (+/- 2,789)
test test1_partial_ord  ... bench:     286,470 ns/iter (+/- 516)
test test2_partial_eq   ... bench:   2,228,997 ns/iter (+/- 34,191)
test test2_partial_ord  ... bench:   1,731,699 ns/iter (+/- 21,756)
test test_match_success ... bench:   1,509,630 ns/iter (+[- 3,765)
```

[Benchmark](https://gist.github.com/Marwes/7c0b3468d0cae972a2b4)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants