diff options
author | The 8472 <git@infinite-source.de> | 2023-03-05 16:15:16 +0100 |
---|---|---|
committer | The 8472 <git@infinite-source.de> | 2023-04-27 22:29:03 +0200 |
commit | 4907dac54cc43d44bd6df87636e545756d110957 (patch) | |
tree | d6b8fcb18473ec627073db3466f181876eb3877e /compiler/rustc_abi | |
parent | faf2da3e2f04f525784fd4d41375e96a8356f4e3 (diff) | |
download | rust-4907dac54cc43d44bd6df87636e545756d110957.tar.gz |
don't promote large fields to higher alignments if that would affect niche placement
Diffstat (limited to 'compiler/rustc_abi')
-rw-r--r-- | compiler/rustc_abi/src/layout.rs | 37 |
1 files changed, 24 insertions, 13 deletions
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index a833302d566..0b0fea4c500 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -772,19 +772,6 @@ fn univariant( if optimize { let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() }; let optimizing = &mut inverse_memory_index.raw[..end]; - let effective_field_align = |layout: Layout<'_>| { - if let Some(pack) = pack { - // return the packed alignment in bytes - layout.align().abi.min(pack).bytes() - } else { - // returns log2(effective-align). - // This is ok since `pack` applies to all fields equally. - // The calculation assumes that size is an integer multiple of align, except for ZSTs. - // - // group [u8; 4] with align-4 or [u8; 6] with align-2 fields - layout.align().abi.bytes().max(layout.size().bytes()).trailing_zeros() as u64 - } - }; // If `-Z randomize-layout` was enabled for the type definition we can shuffle // the field ordering to try and catch some code making assumptions about layouts @@ -801,6 +788,30 @@ fn univariant( } // Otherwise we just leave things alone and actually optimize the type's fields } else { + let max_field_align = fields.iter().map(|f| f.align().abi.bytes()).max().unwrap_or(1); + let any_niche = fields.iter().any(|f| f.largest_niche().is_some()); + let effective_field_align = |layout: Layout<'_>| { + if let Some(pack) = pack { + // return the packed alignment in bytes + layout.align().abi.min(pack).bytes() + } else { + // returns log2(effective-align). + // This is ok since `pack` applies to all fields equally. + // The calculation assumes that size is an integer multiple of align, except for ZSTs. + // + // group [u8; 4] with align-4 or [u8; 6] with align-2 fields + let align = layout.align().abi.bytes(); + let size = layout.size().bytes(); + let size_as_align = align.max(size).trailing_zeros(); + let size_as_align = if any_niche { + max_field_align.trailing_zeros().min(size_as_align) + } else { + size_as_align + }; + size_as_align as u64 + } + }; + match kind { StructKind::AlwaysSized | StructKind::MaybeUnsized => { optimizing.sort_by_key(|&x| { |