rustc: correctly transform memory_index mappings for generators.#62072
Merged
bors merged 1 commit intorust-lang:masterfrom Jun 26, 2019
Merged
rustc: correctly transform memory_index mappings for generators.#62072bors merged 1 commit intorust-lang:masterfrom
bors merged 1 commit intorust-lang:masterfrom
Conversation
Centril
reviewed
Jun 23, 2019
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
a750aee to
1fc9365
Compare
tmandry
approved these changes
Jun 23, 2019
Member
tmandry
left a comment
There was a problem hiding this comment.
r=me after my comment.
Looks good, I knew there was a smarter way of doing it but sorting was so much easier ;)
I think my original plan was to replace sorting of the combined memory indices with a merge sort, which would also be O(n). (Or maybe I hallucinated that after the fact, I can’t remember.) I think both ways would work. Regardless, I’m happy to get this back to linear time.
1fc9365 to
edc2159
Compare
edc2159 to
fad27df
Compare
Member
Author
|
@bors r=tmandry |
Collaborator
|
📌 Commit fad27df has been approved by |
Collaborator
bors
added a commit
that referenced
this pull request
Jun 26, 2019
rustc: correctly transform memory_index mappings for generators. Fixes #61793, closes #62011 (previous attempt at fixing #61793). During #60187, I made the mistake of suggesting that the (re-)computation of `memory_index` in `ty::layout`, after generator-specific logic split/recombined fields, be done off of the `offsets` of those fields (which needed to be computed anyway), as opposed to the `memory_index`. `memory_index` maps each field to its in-memory order index, which ranges over the same `0..n` values as the fields themselves, making it a bijective mapping, and more specifically a permutation (indeed, it's the permutation resulting from field reordering optimizations). Each field has an unique "memory index", meaning a sort based on them, even an unstable one, will not put them in the wrong order. But offsets don't have that property, because of ZSTs (which do not increase the offset), so sorting based on the offset of fields alone can (and did) result in wrong orders. Instead of going back to sorting based on (slices/subsets of) `memory_index`, or special-casing ZSTs to make sorting based on offsets produce the right results (presumably), as #62011 does, I opted to drop sorting altogether and focus on `O(n)` operations involving *permutations*: * a permutation is easily inverted (see the `invert_mapping` `fn`) * an `inverse_memory_index` was already employed in other parts of the `ty::layout` code (that is, a mapping from memory order to field indices) * inverting twice produces the original permutation, so you can invert, modify, and invert again, if it's easier to modify the inverse mapping than the direct one * you can modify/remove elements in a permutation, as long as the result remains dense (i.e. using every integer in `0..len`, without gaps) * for splitting a `0..n` permutation into disjoint `0..x` and `x..n` ranges, you can pick the elements based on a `i < x` / `i >= x` predicate, and for the latter, also subtract `x` to compact the range to `0..n-x` * in the general case, for taking an arbitrary subset of the permutation, you need a renumbering from that subset to a dense `0..subset.len()` - but notably, this is still `O(n)`! * you can merge permutations, as long as the result remains disjoint (i.e. each element is unique) * for concatenating two `0..n` and `0..m` permutations, you can renumber the elements in the latter to `n..n+m` * some of these operations can be combined, and an inverse mapping (be it a permutation or not) can still be used instead of a forward one by changing the "domain" of the loop performing the operation I wish I had a nicer / more mathematical description of the recombinations involved, but my focus was to fix the bug (in a way which preserves information more directly than sorting would), so I may have missed potential changes in the surrounding generator layout code, that would make this all more straight-forward. r? @tmandry
Collaborator
|
☀️ Test successful - checks-travis, status-appveyor |
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #61793, closes #62011 (previous attempt at fixing #61793).
During #60187, I made the mistake of suggesting that the (re-)computation of
memory_indexinty::layout, after generator-specific logic split/recombined fields, be done off of theoffsetsof those fields (which needed to be computed anyway), as opposed to thememory_index.memory_indexmaps each field to its in-memory order index, which ranges over the same0..nvalues as the fields themselves, making it a bijective mapping, and more specifically a permutation (indeed, it's the permutation resulting from field reordering optimizations).Each field has an unique "memory index", meaning a sort based on them, even an unstable one, will not put them in the wrong order. But offsets don't have that property, because of ZSTs (which do not increase the offset), so sorting based on the offset of fields alone can (and did) result in wrong orders.
Instead of going back to sorting based on (slices/subsets of)
memory_index, or special-casing ZSTs to make sorting based on offsets produce the right results (presumably), as #62011 does, I opted to drop sorting altogether and focus onO(n)operations involving permutations:invert_mappingfn)inverse_memory_indexwas already employed in other parts of thety::layoutcode (that is, a mapping from memory order to field indices)0..len, without gaps)0..npermutation into disjoint0..xandx..nranges, you can pick the elements based on ai < x/i >= xpredicate, and for the latter, also subtractxto compact the range to0..n-x0..subset.len()- but notably, this is stillO(n)!0..nand0..mpermutations, you can renumber the elements in the latter ton..n+mI wish I had a nicer / more mathematical description of the recombinations involved, but my focus was to fix the bug (in a way which preserves information more directly than sorting would), so I may have missed potential changes in the surrounding generator layout code, that would make this all more straight-forward.
r? @tmandry