-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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
Fix for #62691: use the largest niche across all fields #70411
Changes from 2 commits
4d77d01
81006f6
bb3e513
0b00c20
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -282,8 +282,6 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { | |
|
||
let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align }; | ||
|
||
let mut sized = true; | ||
let mut offsets = vec![Size::ZERO; fields.len()]; | ||
let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).collect(); | ||
|
||
let mut optimize = !repr.inhibit_struct_field_reordering_opt(); | ||
|
@@ -320,6 +318,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { | |
// At the bottom of this function, we invert `inverse_memory_index` to | ||
// produce `memory_index` (see `invert_mapping`). | ||
|
||
let mut sized = true; | ||
let mut offsets = vec![Size::ZERO; fields.len()]; | ||
let mut offset = Size::ZERO; | ||
let mut largest_niche = None; | ||
let mut largest_niche_available = 0; | ||
|
@@ -907,18 +907,26 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { | |
let count = (niche_variants.end().as_u32() | ||
- niche_variants.start().as_u32() | ||
+ 1) as u128; | ||
// FIXME(#62691) use the largest niche across all fields, | ||
// not just the first one. | ||
for (field_index, &field) in variants[i].iter().enumerate() { | ||
let niche = match &field.largest_niche { | ||
Some(niche) => niche, | ||
_ => continue, | ||
}; | ||
let (niche_start, niche_scalar) = match niche.reserve(self, count) { | ||
Some(pair) => pair, | ||
None => continue, | ||
}; | ||
|
||
let mut niche_size = 0; | ||
if let Some((field_index, niche, niche_start, niche_scalar)) = | ||
variants[i].iter().enumerate().fold(None, |acc, (j, &field)| { | ||
let niche = match &field.largest_niche { | ||
Some(niche) => niche, | ||
_ => return acc, | ||
}; | ||
let ns = niche.available(dl); | ||
if ns <= niche_size { | ||
return acc; | ||
} | ||
match niche.reserve(self, count) { | ||
Some(pair) => { | ||
niche_size = ns; | ||
Some((j, niche, pair.0, pair.1)) | ||
} | ||
None => acc, | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider sprinkling some comments here btw, and/or extracting functions :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hopefully we can keep something close to the first commit, as it's more functional and way easier to explain as "find the largest niche among the fields" + "make sure it can fit our variant |
||
}) | ||
{ | ||
let mut align = dl.aggregate_align; | ||
let st = variants | ||
.iter_enumerated() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need this complication, just have
.max_by_key(|(_, niche, _)| niche.available(dl))
before.and_then(|(_, niche)| Some((i, niche, niche.reserve(self, count)?)))
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted to do that but that's not exactly the same thing. If it fails for the largest niche, but would have succeeded for a smaller niche, we would end up with None instead of using the smaller niche.
Now, maybe this cannot succeed for a smaller niche and fail for a bigger one so in that case that would be indeed best.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that's why we want bigger niches in general: they succeed strictly more often.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is what i've done now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But looking at the code of Niche::reserve, it seems it can still fail if
valid_range_contains
despite being the largest niche while a smaller niche would work. or is that really unlikely?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The calculations are equivalent, I think I even double-checked them using bruteforce for small bitwidths.
niche.reserve(count)
is checkingniche.available() >= count
but using values it has to compute anyway (i.e. the remaining validity range), instead of actually usingavailable
.