From: Pietro Albini Date: Sun, 18 Nov 2018 22:24:34 +0000 (+0100) Subject: Rollup merge of #55834 - ogoffart:union-abi, r=eddyb X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=4a52c5625c08f4c9df8f7367d999b6828c20a83a;hp=-c;p=rust.git Rollup merge of #55834 - ogoffart:union-abi, r=eddyb Forward the ABI of the non-zero sized fields of an union if they have the same ABI This is supposed to fix the performence regression of using MaybeUninit in https://github.com/rust-lang/rust/pull/54668 --- 4a52c5625c08f4c9df8f7367d999b6828c20a83a diff --combined src/librustc/ty/layout.rs index 79324bd97a3,0b00cfc2d7f..d7fb8da7acd --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@@ -697,7 -697,9 +697,9 @@@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a Align::from_bytes(repr_align, repr_align).unwrap()); } + let optimize = !def.repr.inhibit_union_abi_opt(); let mut size = Size::ZERO; + let mut abi = Abi::Aggregate { sized: true }; let index = VariantIdx::new(0); for field in &variants[index] { assert!(!field.is_unsized()); @@@ -708,13 -710,44 +710,44 @@@ } else { align = align.max(field.align); } + + // If all non-ZST fields have the same ABI, forward this ABI + if optimize && !field.is_zst() { + // Normalize scalar_unit to the maximal valid range + let field_abi = match &field.abi { + Abi::Scalar(x) => Abi::Scalar(scalar_unit(x.value)), + Abi::ScalarPair(x, y) => { + Abi::ScalarPair( + scalar_unit(x.value), + scalar_unit(y.value), + ) + } + Abi::Vector { element: x, count } => { + Abi::Vector { + element: scalar_unit(x.value), + count: *count, + } + } + Abi::Uninhabited | + Abi::Aggregate { .. } => Abi::Aggregate { sized: true }, + }; + + if size == Size::ZERO { + // first non ZST: initialize 'abi' + abi = field_abi; + } else if abi != field_abi { + // different fields have different ABI: reset to Aggregate + abi = Abi::Aggregate { sized: true }; + } + } + size = cmp::max(size, field.size); } return Ok(tcx.intern_layout(LayoutDetails { variants: Variants::Single { index }, fields: FieldPlacement::Union(variants[index].len()), - abi: Abi::Aggregate { sized: true }, + abi, align, size: size.abi_align(align) })); @@@ -1287,7 -1320,7 +1320,7 @@@ /// Type size "skeleton", i.e. the only information determining a type's size. /// While this is conservative, (aside from constant sizes, only pointers, /// newtypes thereof and null pointer optimized enums are allowed), it is -/// enough to statically check common usecases of transmute. +/// enough to statically check common use cases of transmute. #[derive(Copy, Clone, Debug)] pub enum SizeSkeleton<'tcx> { /// Any statically computable Layout. diff --combined src/librustc/ty/mod.rs index 96f4b1ef8e3,9553d124483..a474065b5cd --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@@ -515,10 -515,6 +515,10 @@@ pub struct TyS<'tcx> outer_exclusive_binder: ty::DebruijnIndex, } +// `TyS` is used a lot. Make sure it doesn't unintentionally get bigger. +#[cfg(target_arch = "x86_64")] +static_assert!(MEM_SIZE_OF_TY_S: ::std::mem::size_of::>() == 32); + impl<'tcx> Ord for TyS<'tcx> { fn cmp(&self, other: &TyS<'tcx>) -> Ordering { self.sty.cmp(&other.sty) @@@ -1998,6 -1994,12 +1998,12 @@@ impl ReprOptions pub fn inhibit_struct_field_reordering_opt(&self) -> bool { !(self.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty() || (self.pack == 1) } + + /// Returns true if this `#[repr()]` should inhibit union abi optimisations + pub fn inhibit_union_abi_opt(&self) -> bool { + self.c() + } + } impl<'a, 'gcx, 'tcx> AdtDef { @@@ -2130,7 -2132,7 +2136,7 @@@ } #[inline] - pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> GenericPredicates<'gcx> { + pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Lrc> { tcx.predicates_of(self.did) } @@@ -2373,8 -2375,8 +2379,8 @@@ def_id: sized_trait, substs: tcx.mk_substs_trait(ty, &[]) }).to_predicate(); - let predicates = tcx.predicates_of(self.did).predicates; - if predicates.into_iter().any(|(p, _)| p == sized_predicate) { + let predicates = &tcx.predicates_of(self.did).predicates; + if predicates.iter().any(|(p, _)| *p == sized_predicate) { vec![] } else { vec![ty] @@@ -2400,7 -2402,7 +2406,7 @@@ impl<'a, 'gcx, 'tcx> FieldDef /// Represents the various closure traits in the Rust language. This /// will determine the type of the environment (`self`, in the -/// desuaring) argument that the closure expects. +/// desugaring) argument that the closure expects. /// /// You can get the environment type of a closure using /// `tcx.closure_env_ty()`.