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

Move Option::as_slice to an always-sound implementation #108623

Merged
merged 2 commits into from
Mar 13, 2023

Conversation

scottmcm
Copy link
Member

@scottmcm scottmcm commented Mar 1, 2023

This approach depends on CSE to not have any branches or selects when the guessed offset is correct -- which it always will be right now -- but to also be sound (just less efficient) if the layout algorithms change such that the guess is incorrect.

The codegen test confirms that CSE handles this as expected, leaving the optimal codegen.

cc JakobDegen #108545

@rustbot
Copy link
Collaborator

rustbot commented Mar 1, 2023

r? @m-ou-se

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

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Mar 1, 2023
@rustbot

This comment was marked as resolved.

@scottmcm scottmcm force-pushed the try-different-as-slice-impl branch from 5fcedf2 to c2df8b9 Compare March 1, 2023 19:02
// CHECK-NOT: select
// CHECK-NOT: br
// CHECK-NOT: switch
// CHECK-NOT: icmp
o.as_slice()
Copy link
Member Author

@scottmcm scottmcm Mar 1, 2023

Choose a reason for hiding this comment

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

Output of the codegen test on my machine, in case it helps a reviewer:

; Function Attrs: mustprogress nofree nosync nounwind willreturn uwtable
define { ptr, i64 } @u64_opt_as_slice(ptr noalias noundef readonly align 8 dereferenceable(16) %o) unnamed_addr #0 {
start:
  %_3.i = load i64, ptr %o, align 8, !range !1, !alias.scope !2, !noundef !5
  %payload.i = getelementptr inbounds { i64, i64 }, ptr %o, i64 0, i32 1
  %0 = insertvalue { ptr, i64 } undef, ptr %payload.i, 0
  %1 = insertvalue { ptr, i64 } %0, i64 %_3.i, 1
  ret { ptr, i64 } %1
}

; Function Attrs: mustprogress nofree nosync nounwind willreturn uwtable
define { ptr, i64 } @nonzero_u64_opt_as_slice(ptr noalias noundef readonly align 8 dereferenceable(8) %o) unnamed_addr #0 {
start:
  %0 = load i64, ptr %o, align 8, !alias.scope !6, !noundef !5
  %.not3.i = icmp ne i64 %0, 0
  %len.i = zext i1 %.not3.i to i64
  %1 = insertvalue { ptr, i64 } undef, ptr %o, 0
  %2 = insertvalue { ptr, i64 } %1, i64 %len.i, 1
  ret { ptr, i64 } %2
}

!1 = !{i64 0, i64 2}

@scottmcm
Copy link
Member Author

scottmcm commented Mar 4, 2023

Let's flip this to a hopefully-less-busy non-libs-api reviewer:
r? @the8472

@rustbot rustbot assigned the8472 and unassigned m-ou-se Mar 4, 2023

// These are all true by construction, but to make it obvious:
assert!(offset >= 0);
assert!((offset as usize) <= mem::size_of::<Self>());
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, same point as 8472 above, but I don't really see why this has to hold in the face of very silly layouts for Option<MaybeUninit<T>>. The other two I agree with.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yup, agreed with both of you. Enough spurious padding and it could be out of bounds.

@rustbot author

@rustbot rustbot 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 Mar 12, 2023
This approach depends on CSE to not have any branches or selects when the guessed offset is correct -- which it always will be right now -- but to also be *sound* (just less efficient) if the layout algorithms change such that the guess is incorrect.
@scottmcm scottmcm force-pushed the try-different-as-slice-impl branch from c2df8b9 to f6a57c1 Compare March 12, 2023 04:29
@scottmcm
Copy link
Member Author

As I was doing this, I realized that the layout-optimized case is actually a subset of the "guess is totally wrong case", so I think this came out pretty elegantly.

@rustbot ready

@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 Mar 12, 2023
@the8472
Copy link
Member

the8472 commented Mar 12, 2023

Maybe this could use a FIXME that what we really want here is a offset_of into an enum variant, if such a feature ever materializes. But we don't even have an RFC open that we could point to.

r=me either way


let max_offset = mem::size_of::<Self>() - mem::size_of::<T>();
if offset as usize <= max_offset {
// The offset is at least inside the object, so let's try it.
Copy link
Member

Choose a reason for hiding this comment

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

Wouldn't this be "inside or one past the end"?

Copy link
Member Author

Choose a reason for hiding this comment

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

Only if T is a ZST, since I'm checking the offset against sizeof(Option<T>) - sizeof(T), not just against sizeof(Option<T>).

("Inside" is always a hard question when it comes to ZSTs...)

@scottmcm
Copy link
Member Author

@bors r=the8472

@bors
Copy link
Contributor

bors commented Mar 12, 2023

📌 Commit e975057 has been approved by the8472

It is now in the queue for this repository.

@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 Mar 12, 2023
@bors
Copy link
Contributor

bors commented Mar 13, 2023

⌛ Testing commit e975057 with merge cf8d98b...

@bors
Copy link
Contributor

bors commented Mar 13, 2023

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

1 similar comment
@bors
Copy link
Contributor

bors commented Mar 13, 2023

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

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Mar 13, 2023
@bors bors merged commit cf8d98b into rust-lang:master Mar 13, 2023
@rustbot rustbot added this to the 1.70.0 milestone Mar 13, 2023
@scottmcm scottmcm deleted the try-different-as-slice-impl branch March 13, 2023 17:33
@rust-timer
Copy link
Collaborator

Finished benchmarking commit (cf8d98b): comparison URL.

Overall result: ❌ regressions - ACTION NEEDED

Next Steps: If you can justify the regressions found in this perf run, please indicate this with @rustbot label: +perf-regression-triaged along with sufficient written justification. If you cannot justify the regressions please open an issue or create a new PR that fixes the regressions, add a comment linking to the newly created issue or PR, and then add the perf-regression-triaged label to this PR.

@rustbot label: +perf-regression
cc @rust-lang/wg-compiler-performance

Instruction count

This is a highly reliable metric that was used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
0.8% [0.8%, 0.9%] 3
Regressions ❌
(secondary)
0.6% [0.4%, 0.7%] 3
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 0.8% [0.8%, 0.9%] 3

Max RSS (memory usage)

Results

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
1.4% [1.4%, 1.4%] 1
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-2.9% [-2.9%, -2.9%] 1
All ❌✅ (primary) 1.4% [1.4%, 1.4%] 1

Cycles

Results

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
1.0% [1.0%, 1.0%] 1
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) - - 0

@rustbot rustbot added the perf-regression Performance regression. label Mar 13, 2023
@Mark-Simulacrum Mark-Simulacrum added the perf-regression-triaged The performance regression has been triaged. label Mar 14, 2023
@cuviper cuviper mentioned this pull request Mar 14, 2023
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. perf-regression Performance regression. perf-regression-triaged The performance regression has been triaged. 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.

8 participants