Repository navigation
Conversation
|
r? @jieyouxu rustbot has assigned @jieyouxu. Use Why was this reviewer chosen?The reviewer was selected based on:
|
This comment has been minimized.
This comment has been minimized.
c8a5f50 to
80bc421
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Thanks. Broadly seems like a good readability improvement. Some nits. I left review comments commit-by-commit so might show up weirdly.
@rustbot author
| // | ||
| // How can this be nonzero when everything else is a ZST? `others_zst` is true here |
There was a problem hiding this comment.
Isn't others_zst about the other variants rather than fields of the largest variant?
E.g. if you have
#[repr(C)]
struct Foo(u32, bool);then Some variant of Option<Foo> would use the bool as the niche at offset 4. None would be the "others ZST" here.
| align_abi: Align, | ||
| } | ||
|
|
||
| fn try_fixup_non_niche_variants<VariantIdx: Idx, FieldIdx: Idx>( |
There was a problem hiding this comment.
I'm a bit confused by this name 🤔 What this loop is doing is that we're trying to fit niche variants1.
I think there might be a bit of a terminology thing here: say if we have
Option<Foo>
Some { a: u32, b: bool }
None
here None is the niche variant. Some with the bool would be the untagged_variant. Perhaps a better name for this would be try_fit_niche_variants? Or likely more accurate but maybe less straightforward, try_fit_other_variants 🤷 This could really use a doc comment TL;DR-ing the intent, i.e. trying to fit the variants that are not the untagged_variant.
Footnotes
-
That's a bit of a lie, this also handles absent2 variants I think, so it's technically "everything that's not
untagged_variant". But like calling itnon_untagged_variantsis probably trolling. Perhaps confusingly, this is specifically for niche encoding, so absent variants outside ofniche_variantsdoesn't need a tag value. ↩ -
There's more nuance here that absent variants != ZST, and for a variant to qualify as an absent variant it seems that it needs to both satisfy (1) have at least one uninhabited field so it's never constructible, and (2) every field need to be 1-ZST. ↩
| let best_layout = match (tagged_layout, niche_filling_layout) { | ||
| (tl, Some(nl)) => { | ||
| // Pick the smaller layout; otherwise, | ||
| // pick the layout with the larger niche; otherwise, | ||
| // pick tagged as it has simpler codegen. | ||
| use cmp::Ordering::*; | ||
| let niche_size = |l: &LayoutData<FieldIdx, VariantIdx>| { | ||
| l.largest_niche.map_or(0, |n| n.available(dl)) | ||
| }; | ||
| match (tl.size.cmp(&nl.size), niche_size(&tl).cmp(&niche_size(&nl))) { | ||
| (Greater, _) => nl, | ||
| (Equal, Less) => nl, | ||
| _ => tl, | ||
| } | ||
| } | ||
| (tl, None) => tl, | ||
| }; |
There was a problem hiding this comment.
This can probably pull out the niche_filling_layout as an early return, i.e. let Some(nl) = niche_filling_layout else { return Ok(tagged_layout) };. This match seems a bit unnecessarily complex.
| Ok(best_layout) | ||
| } | ||
|
|
||
| fn constructable_variant<'a, VariantIdx, FieldIdx, F>(variant: &IndexSlice<FieldIdx, F>) -> bool |
There was a problem hiding this comment.
I think it's usually spelled constructible. Also, I would call this instead variant_is_inhabited, since I find it a bit more ambiguous as there's also the concept of "absent" in layout.
| } | ||
| } | ||
| } | ||
| let abi = calculate_tagged_abi(calculator, &layout_variants, &variants, size, align, tag); |
There was a problem hiding this comment.
Nit: you can probably lose the borrow on variants, since it's already &IndexSlice<...>
| // However, it is fine to make discr type however large (as an optimisation) | ||
| // after this point – we’ll just truncate the value we load in codegen. |
There was a problem hiding this comment.
Hm, I'd move this comment back to the call-site after sanity_check_ity, it's more like a positional invariant that holds after the sanity check on the call-site.
| // If the alignment is not larger than the chosen discriminant size, | ||
| // don't use the alignment as the final size. |
There was a problem hiding this comment.
This comment no longer belongs here, right? Maybe move it to the .max()?
| let prefix_align = if repr.c() { | ||
| variants | ||
| .iter() | ||
| .flatten() | ||
| .fold(min_ity.align(dl).abi, |prefix_align, field| prefix_align.max(field.align.abi)) | ||
| } else { | ||
| min_ity.align(dl).abi | ||
| }; |
There was a problem hiding this comment.
Maybe pull out a local, like let tag_align = min_ity.align(dl).abi;, it's a bit of a mouthful repeating here.
| } | ||
| } | ||
|
|
||
| fn calculate_tagged_tag<FieldIdx, VariantIdx>( |
There was a problem hiding this comment.
This also adjusts variant field offsets/sizes 🤔 Maybe call this sth like finalize_tag_and_patch_variants (not a fantastic name, but sth to that effect).
| }; | ||
| trace!(?min_negative, ?max_positive); | ||
|
|
||
| // Integer::discr_range_of_repr(tcx, ty, &repr, min, max); |
There was a problem hiding this comment.
This is probably leftover debugging code or sth, drop it?
|
Reminder, once the PR becomes ready for a review, use |
80bc421 to
ce001ad
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. |
Moves layout calculation of enums to its own file, chunks large functions into smaller ones and makes some variables immutable
Motivation: Surely I wasn't the only one who tried to understand niche optimization and enum layout calculation, only to find a 500 lines long function full of mutable variables.
It is a +600-500 PR but reviewing commit-by-commit should be manageable. Commits compile and refactor a single part of layout calculation.