]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #55834 - ogoffart:union-abi, r=eddyb
authorPietro Albini <pietro@pietroalbini.org>
Sun, 18 Nov 2018 22:24:34 +0000 (23:24 +0100)
committerGitHub <noreply@github.com>
Sun, 18 Nov 2018 22:24:34 +0000 (23:24 +0100)
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

1  2 
src/librustc/ty/layout.rs
src/librustc/ty/mod.rs

index 79324bd97a3db4b40771af92b25eba97e4293c9a,0b00cfc2d7fd42f71aaa18de0418413d8f349386..d7fb8da7acd05fca7bffaaff732f7066b5a65b0f
@@@ -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());
                          } 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)
                      }));
  /// 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 96f4b1ef8e32aed3c141e649997fce9140952d5f,9553d1244837c3d75e06d6088696475cac0dbc70..a474065b5cd55fe1911c8a1de888eb53ddf52ac3
@@@ -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::<TyS<'_>>() == 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 {
      }
  
      #[inline]
 -    pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> GenericPredicates<'gcx> {
 +    pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Lrc<GenericPredicates<'gcx>> {
          tcx.predicates_of(self.did)
      }
  
                      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()`.