Repository navigation
Remove redundant PartialOrd chaining methods - #164684
Conversation
This comment was marked as outdated.
This comment was marked as outdated.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Remove redundant `PartialOrd` chaining methods
bee0343 to
a85241c
Compare
This comment was marked as outdated.
This comment was marked as outdated.
This comment has been minimized.
This comment has been minimized.
Remove redundant `PartialOrd` chaining methods
fc2e927 to
2974302
Compare
This comment has been minimized.
This comment has been minimized.
Remove redundant `PartialOrd` chaining methods
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (8a96fbf): comparison URL. Overall result: no relevant changes - no action neededBenchmarking means the PR may be perf-sensitive. Consider adding rollup=never if this change is not fit for rolling up. @rustbot label: -S-waiting-on-perf -perf-regression Instruction countThis perf run didn't have relevant results for this metric. Max RSS (memory usage)Results (secondary 0.3%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (primary 2.4%, secondary -0.6%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeResults (primary -0.1%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Bootstrap: 490.972s -> 489.047s (-0.39%) |
2974302 to
4fc6890
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
|
Thanks for pinging me. I added these methods in the first place, so happy to review here. (I definitely wasn't brave enough to try to add these to the derive, since the derive doesn't include |
|
Interesting, I didn't know about the I'll keep trying around, if it doesn't lead to anything that's fine. |
| bb1: { | ||
| StorageLive(_6); | ||
| _6 = Ge(copy _3, copy _4); | ||
| _6 = Gt(copy _3, copy _4); |
There was a problem hiding this comment.
(this comment is me musing, not a 👍 nor a 👎)
I'm always torn on this kind of change. There's a certain obviousness to "well of course we'll emit a Gt if you use >". But I also agree that it shouldn't matter. But also in LLVM x < 0 stays that way but x <= 0 changes to x < 1 so it might matter. But optimizations should be handling those canonicalizations properly later. But also equivalent things aren't always. …
There was a problem hiding this comment.
I flipped a coin to decide which one to remove
| /// Same as `__chaining_lt`, but for `>` instead of `<`. | ||
| #[inline] | ||
| #[unstable(feature = "partial_ord_chaining_methods", issue = "none")] | ||
| #[doc(hidden)] | ||
| fn __chaining_gt(&self, other: &Rhs) -> ControlFlow<bool> { | ||
| default_chaining_impl(self, other, Ordering::is_gt) | ||
| } |
There was a problem hiding this comment.
Having read through this, I think I quite like it. There's a note I wrote above that this might not be stabilization-track that was in part because needing 4 more just felt messy, and having it drop from 4 to 2 is a massive improvement to that. (Not saying that I now think it ought to get stabilized, necessarily, but at least it's less "this is too icky".)
That said, I think with the change we should lean into the two-vs-four more heavily in the naming and comments. How about changing the names to __chaining_less and __chaining_greater here or __chaining_[lg] or something? I would prefer not saying lt if it's the thing you should use for le as well; I think that makes it less clear.
Then similarly the description would update to not talk about </<=/>/>=, but instead about how the full ordering is represented in the ControlFlow<bool> (and of course continue to say why this is fruitful over Option<Ordering> in some situations).
There was a problem hiding this comment.
I like the less change. I feel like having < and > be implemented by different methods was a mistake ^^
There was a problem hiding this comment.
wasn't entirely sure what you meant by "how the full ordering is represented", so i did it differently.
I think it's #81384 ? |
4fc6890 to
04dd9c4
Compare
|
Interesting. Reading that makes it sound like there were some bigger issues going on with those methods though. I'll take that as more motivation to experiment with |
04dd9c4 to
9ff9ee8
Compare
|
@rustbot ready |
|
On the polarity side: there are some interesting questions about whether one should expect the LHS to be the LHS or not in comparisons. If you have Probably not this PR, but you could consider looking at some of the specific impls to see whether they need the asymmetry support, and delegate from one to the other in symmetric impls. (Are slices and tuples only symmetric? I don't actually remember. Though might also be worth checking with libs(-api) to see whether that's intentional or incidental before relying on it.) |
|
Ah right, polarity only applies when you have both directions... |
Removed the section from the pr description, don't want to gaslight anyone reading the git log. But hey, at least we have a good reason for why we actually need both of these methods in case we ever want to stabilize them ^^ |
| fn chaining_less(left: &[Self], right: &[Self]) -> ControlFlow<bool> { | ||
| match SliceOrd::compare(left, right) { | ||
| Ordering::Equal => ControlFlow::Continue(()), | ||
| ne => ControlFlow::Break(ne.is_lt()), |
There was a problem hiding this comment.
not this PR: looking at this again, now that it doesn't need to be lt specifically, I wonder if changing this to
| ne => ControlFlow::Break(ne.is_lt()), | |
| Ordering::Less => ControlFlow::Break(true), | |
| Ordering::Greater => ControlFlow::Break(false), |
would be better or worse.
It's certainly clear, and avoids the lt mention, but I have no idea whether it'd be better.
There was a problem hiding this comment.
I'll add it to my list of things to try, but I suspect no difference
There was a problem hiding this comment.
In codegen it's a 3-way switch vs two nested brs, so while ideally it wouldn't matter, it's the kind of thing where it's never as obvious as one would like.
| fn __chaining_lt(&self, other: &Self) -> ControlFlow<bool> { | ||
| fn __chaining_less(&self, other: &Self) -> ControlFlow<bool> { | ||
| let (lhs, rhs) = (*self, *other); | ||
| // We arbitrarily pick `<` here. Using `<=` gives the same result. |
There was a problem hiding this comment.
Started #t-compiler/llvm > `lt` vs `le` when you know it's not equal to ask if there's a non-arbitrary choice. Don't need to block on that, of course.
Note that that's ok; we're releasing a change like that in 3 weeks :) #161391 |
|
|
|
Thanks, looking good! I like the note about where the difference happens between @bors r+ rollup=maybe (I'm on the fence for this. it can affect codegen so I worry and would normally put iffy, but also the perf showed clear so probably better to roll it up and it's not supposed to really affect anything) |
I used to be on the review rotation for libcore. I had to leave that a while ago, but I still take reviews from time to time :) |
…uwer Rollup of 6 pull requests Successful merges: - #164383 (handle higher-ranked preds in imperfect derives diagnostic) - #164620 (Wrap expected_ty for cfi-{diag,recover} in with_no_trimmed_paths) - #164684 (Remove redundant `PartialOrd` chaining methods) - #158076 (Offload safe mutable args with `Region` and `PartitioningStrategy`) - #164680 (Add regression test for async fn declared with #[eii]) - #164696 (Add `#[default]` for `newtype_index!`)
Rollup merge of #164684 - maxdexh:partial-ord-chain-api-simplify, r=scottmcm Remove redundant `PartialOrd` chaining methods I'm currently trying to do some optimizations using the `PartialOrd` chaining methods, and I noticed that `__chaining_le` and `__chaining_lt` are actually exactly the same for all implementations (and likewise `__chaining_ge`/`__chaining_gt`). In particular, - `__chaining_le`/`__chaining_lt` returns `Continue(())` if `self == other`, else `Break(self <= other)`/`Break(self < other)` - We require that `a <= b` iff `a < b` or `a == b`. So it doesn't matter (for well-behaved impls) if we break with `self <= other` or `self < other`. - All explicit impls of the chaining methods are in std, and well-behaved, as this is an internal API (except tuples and slices may not be well-behaved if their items aren't. For them, equivalence follows from the equivalence for their items, inductively). - All other impls of the chaining methods are using the default impl, based on matching `Option<Ordering>` from `partial_cmp`: https://github.com/rust-lang/rust/blob/1731faea0da5b4ebf881d8e53f98066c17a74711/library/core/src/cmp.rs#L1613-L1617 Using `Ordering::is_le`/`Ordering::is_lt` for `p` is the same here, as `Some(Equal)` gets matched early. Thus, even non-well-behaved `PartialOrd` impls (i.e. those with non-conforming `le`/`lt`/`eq` methods) have identically behaving `__chaining_le`/`__chaining_lt`. We can conclude that merging `__chaining_le`/`__chaining_lt` doesn't change behavior. You can verify the above points by looking at the diff, as every such method pair has been touched. r? scottmcm Picking you as reviewer because you also reviewed my earlier PR that optimized chaining ops on tuples, and appear to also have done some work on these methods before. Feel free to reroll.
View all comments
I'm currently trying to do some optimizations using the
PartialOrdchaining methods, and I noticed that__chaining_leand__chaining_ltare actually exactly the same for all implementations (and likewise__chaining_ge/__chaining_gt).In particular,
__chaining_le/__chaining_ltreturnsContinue(())ifself == other, elseBreak(self <= other)/Break(self < other)a <= biffa < bora == b. So it doesn't matter (for well-behaved impls) if we break withself <= otherorself < other.Option<Ordering>frompartial_cmp:rust/library/core/src/cmp.rs
Lines 1613 to 1617 in 1731fae
Using
Ordering::is_le/Ordering::is_ltforpis the same here, asSome(Equal)gets matched early. Thus, even non-well-behavedPartialOrdimpls (i.e. those with non-conformingle/lt/eqmethods) have identically behaving__chaining_le/__chaining_lt.We can conclude that merging
__chaining_le/__chaining_ltdoesn't change behavior. You can verify the above points by looking at the diff, as every such method pair has been touched.r? scottmcm
Picking you as reviewer because you also reviewed my earlier PR that optimized chaining ops on tuples, and appear to also have done some work on these methods before. Feel free to reroll.