Skip to content
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

Carefully remove bounds checks from some chunk iterator functions #86988

Merged
merged 5 commits into from
Feb 1, 2022

Conversation

thomcc
Copy link
Member

@thomcc thomcc commented Jul 8, 2021

So, I was writing code that requires the equivalent of rchunks(N).rev() (which isn't the same as forward chunks(N) — in particular, if the buffer length is not a multiple of N, I must handle the "remainder" first).

I happened to look at the codegen output of the function (I was actually interested in whether or not a nested loop was being unrolled — it was), and noticed that in the outer rchunks(n).rev() loop, LLVM seemed to be unable to remove the bounds checks from the iteration: https://rust.godbolt.org/z/Tnz4MYY8f (this panic was from the split_at in RChunks::next_back).

After doing some experimentation, it seems all of the next_back in the non-exact chunk iterators have the issue: (Chunks::next_back, RChunks::next_back, ChunksMut::next_back, and RChunksMut::next_back)...

Even worse, the forward rchunks iterators sometimes have the issue as well (... but only sometimes). For example https://rust.godbolt.org/z/oGhbqv53r has bounds checks, but if I uncomment the loop body, it manages to remove the check (which is bizarre, since I'd expect the opposite...). I suspect it's highly dependent on the surrounding code, so I decided to remove the bounds checks from them anyway. Overall, this change includes:

  • All next_back functions on the non-Exact iterators (e.g. R?Chunks(Mut)?).
  • All next functions on the non-exact rchunks iterators (e.g. RChunks(Mut)?).

I wasn't able to catch any of the other chunk iterators failing to remove the bounds checks (I checked iterations over r?chunks(_exact)?(_mut)? with constant chunk sizes under -O3, -Os, and -Oz), which makes sense, since these were the cases where it was harder to prove the bounds check correct to remove...

In fact, it took quite a bit of thinking to convince myself that using unchecked_ here was valid — so I'm not really surprised that LLVM had trouble (although compilers are slightly better at this sort of reasoning than humans). A consequence of that is the fact that the // SAFETY comment for these are... kinda long...


I didn't do this for, or even think about it for, any of the other iteration methods; just next and next_back (where it mattered). If this PR is accepted, I'll file a follow up for someone (possibly me) to look at the others later (in particular, nth/nth_back looked like they had similar logic), but I wanted to do this now, as IMO next/next_back are the most important here, since they're what gets used by the iteration protocol.


Note: While I don't expect this to impact performance directly, the panic is a side effect, which would otherwise not exist in these loops. That is, this could prevent the compiler from being able to move/remove/otherwise rework a loop over these iterators (as an example, it could not delete the code for a loop whose body computes a value which doesn't get used).

Also, some like to be able to have confidence this code has no panicking branches in the optimized code, and "no bounds checks" is kinda part of the selling point of Rust's iterators anyway.

@rust-highfive
Copy link
Collaborator

r? @kennytm

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jul 8, 2021
library/core/src/slice/iter.rs Outdated Show resolved Hide resolved
library/core/src/slice/iter.rs Outdated Show resolved Hide resolved
library/core/src/slice/iter.rs Outdated Show resolved Hide resolved
library/core/src/slice/iter.rs Outdated Show resolved Hide resolved
library/core/src/slice/iter.rs Outdated Show resolved Hide resolved
@JohnCSimon JohnCSimon added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 25, 2021
@JohnCSimon JohnCSimon added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Aug 15, 2021
@inquisitivecrystal inquisitivecrystal added the T-libs Relevant to the library team, which will review and decide on the PR/issue. label Aug 24, 2021
@the8472
Copy link
Member

the8472 commented Sep 8, 2021

taking over reviews for this one

r? @the8472

@rust-highfive rust-highfive assigned the8472 and unassigned kennytm Sep 8, 2021
@the8472 the8472 added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 8, 2021
@JohnCSimon
Copy link
Member

Ping from triage:
@thomcc - Can you please post the status of this PR?

@thomcc
Copy link
Member Author

thomcc commented Sep 28, 2021

Yes, but probably not until the weekend

@JohnCSimon JohnCSimon added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Oct 19, 2021
@thomcc thomcc force-pushed the chunky-splitz-says-no-checking branch from 6fdbf2f to 1f8fb58 Compare October 30, 2021 03:02
@thomcc
Copy link
Member Author

thomcc commented Oct 30, 2021

Current status: The code works fine, and I've tried to remove the repetition from the safety comments, which is probably1 for the best.

Anyway, I guess it can be reviewed now? I don't know that I can improve the safety comments further, but hopefully it's enough? That said, I'm willing to apply suggestions if they're suitably concrete2.

Footnotes

  1. They're arguably less precise now — you can't directly apply Chunks::next_back to e.g. ChunksMut::next_back — but it's probably good enough in practice for it to be clear why it's safe.

    I didn't do this initially because I was worried about things varying, but maintaining all these nearly-equivalent-but-slightly-different safety comments would suck, and it's not exactly clear how to pull it out into a common place (they're all necessarily slightly different for similar reasons to why the iterators can't reuse eachother internally).

  2. For example, I'm not exactly sure what to do with a suggestion to use mathematical notation (sorry).

@the8472
Copy link
Member

the8472 commented Oct 30, 2021

The comment length looks manageable now and the contents are ok too.

I looked over the existing tests and it appears that there are no explicit tests for next/next_back that would cover all branches. Maybe the tests for count() used to in the forward direction but there has been a separate implementation for that for quite some time now.

@JohnCSimon JohnCSimon added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 31, 2021
@JohnCSimon JohnCSimon added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Dec 5, 2021
Copy link
Member

@the8472 the8472 left a comment

Choose a reason for hiding this comment

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

@JohnCSimon this should be waiting-on-author.

To make my previous comment more explicit, since this adds unsafe code it would be good to have test-coverage for it and the existing tests don't look like they cover it entirely.
Specifically Chunks::next_back returning Some doesn't appear to be covered, the None case is covered by test_chunks_nth_back.

@the8472 the8472 added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Dec 31, 2021
@thomcc
Copy link
Member Author

thomcc commented Dec 31, 2021

Ah, right, I forgot about this. I'll get to it later this weekend.

@the8472
Copy link
Member

the8472 commented Jan 18, 2022

@thomcc ping, long weekend? 😄

@thomcc
Copy link
Member Author

thomcc commented Jan 18, 2022

😅 I'll try to get to it when I find some time. Busy lately, unfortunately.

@thomcc thomcc force-pushed the chunky-splitz-says-no-checking branch from 7a1a939 to 9c62455 Compare February 1, 2022 01:35
@thomcc
Copy link
Member Author

thomcc commented Feb 1, 2022

Terribly sorry about the delay, I've added tests. They should cover both the exact size and remainder1 cases, for all functions that I changed.

Footnotes

  1. Well, you know what I mean — I didn't the change _exact fns, so I guess technically there's no remainder.

@thomcc
Copy link
Member Author

thomcc commented Feb 1, 2022

Let's try....

@rustbot ready

(Yay, it worked)

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Feb 1, 2022
@the8472
Copy link
Member

the8472 commented Feb 1, 2022

@bors r+ rollup=never

I'm not seeing much chunks use in the compiler itself but let's skip rollup just in case some lib uses it.

@bors
Copy link
Contributor

bors commented Feb 1, 2022

📌 Commit 9c62455 has been approved by the8472

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Feb 1, 2022
@bors
Copy link
Contributor

bors commented Feb 1, 2022

⌛ Testing commit 9c62455 with merge 547f2ba...

@bors
Copy link
Contributor

bors commented Feb 1, 2022

☀️ Test successful - checks-actions
Approved by: the8472
Pushing 547f2ba to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Feb 1, 2022
@bors bors merged commit 547f2ba into rust-lang:master Feb 1, 2022
@rustbot rustbot added this to the 1.60.0 milestone Feb 1, 2022
@rust-timer
Copy link
Collaborator

Finished benchmarking commit (547f2ba): comparison url.

Summary: This benchmark run did not return any relevant results.

If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf.

@rustbot label: -perf-regression

@thomcc thomcc deleted the chunky-splitz-says-no-checking branch February 1, 2022 20:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants