Skip to content

Commit

Permalink
Auto merge of #45225 - eddyb:trans-abi, r=<try>
Browse files Browse the repository at this point in the history
Refactor type memory layouts and ABIs, to be more general and easier to optimize.

To combat combinatorial explosion, type layouts are now described through 3 orthogonal properties:
* `Variants` describes the plurality of sum types (where applicable)
  * `Single` is for one inhabited/active variant, including all C `struct`s and `union`s
  * `Tagged` has its variants discriminated by an integer tag, including C `enum`s
  * `NicheFilling` uses otherwise-invalid values ("niches") for all but one of its inhabited variants
* `FieldPlacement` describes the number and memory offsets of fields (if any)
  * `Union` has all its fields at offset `0`
  * `Array` has offsets that are a multiple of its `stride`; guarantees all fields have one type
  * `Arbitrary` records all the field offsets, which can be out-of-order
* `Abi` describes how values of the type should be passed around, including for FFI
  * `Uninhabited` corresponds to no values, associated with unreachable control-flow
  * `Scalar` is ABI-identical to its only integer/floating-point/pointer "scalar component"
  * `ScalarPair` has two "scalar components", but only applies to the Rust ABI
  * `Vector` is for SIMD vectors, typically `#[repr(simd)]` `struct`s in Rust
  * `Aggregate` has arbitrary contents, including all non-transparent C `struct`s and `union`s

Size optimizations implemented so far:
* ignoring uninhabited variants (i.e. containing uninhabited fields), e.g.:
  * `Option<!>` is 0 bytes
  * `Result<T, !>` has the same size as `T`
* using arbitrary niches, not just `0`, to represent a data-less variant, e.g.:
  * `Option<bool>`, `Option<Option<bool>>`, `Option<Ordering>` are all 1 byte
  * `Option<char>` is 4 bytes
* using a range of niches to represent *multiple* data-less variants, e.g.:
  * `enum E { A(bool), B, C, D }` is 1 byte

Code generation now takes advantage of `Scalar` and `ScalarPair` to, in more cases, pass around scalar components as immediates instead of indirectly, through pointers into temporary memory, while avoiding LLVM's "first-class aggregates", and there's more untapped potential here.

Closes #44426, fixes #5977, fixes #14540, fixes #43278.
  • Loading branch information
bors committed Oct 29, 2017
2 parents 7d475a2 + cac77ac commit fa5efe4
Show file tree
Hide file tree
Showing 75 changed files with 4,808 additions and 5,505 deletions.
18 changes: 14 additions & 4 deletions src/liballoc/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ impl<T> Place<T> for IntermediateBox<T> {
unsafe fn finalize<T>(b: IntermediateBox<T>) -> Box<T> {
let p = b.ptr as *mut T;
mem::forget(b);
mem::transmute(p)
Box::from_raw(p)
}

fn make_place<T>() -> IntermediateBox<T> {
Expand Down Expand Up @@ -300,7 +300,10 @@ impl<T: ?Sized> Box<T> {
issue = "27730")]
#[inline]
pub unsafe fn from_unique(u: Unique<T>) -> Self {
mem::transmute(u)
#[cfg(stage0)]
return mem::transmute(u);
#[cfg(not(stage0))]
return Box(u);
}

/// Consumes the `Box`, returning the wrapped raw pointer.
Expand Down Expand Up @@ -362,7 +365,14 @@ impl<T: ?Sized> Box<T> {
issue = "27730")]
#[inline]
pub fn into_unique(b: Box<T>) -> Unique<T> {
unsafe { mem::transmute(b) }
#[cfg(stage0)]
return unsafe { mem::transmute(b) };
#[cfg(not(stage0))]
return {
let unique = b.0;
mem::forget(b);
unique
};
}
}

Expand Down Expand Up @@ -627,7 +637,7 @@ impl Box<Any + Send> {
pub fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any + Send>> {
<Box<Any>>::downcast(self).map_err(|s| unsafe {
// reapply the Send marker
mem::transmute::<Box<Any>, Box<Any + Send>>(s)
Box::from_raw(Box::into_raw(s) as *mut (Any + Send))
})
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@
#![feature(conservative_impl_trait)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(i128)]
#![feature(i128_type)]
#![feature(inclusive_range)]
#![feature(inclusive_range_syntax)]
#![cfg_attr(windows, feature(libc))]
#![feature(never_type)]
#![feature(nonzero)]
Expand Down
11 changes: 10 additions & 1 deletion src/librustc/lint/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ use middle::privacy::AccessLevels;
use rustc_serialize::{Decoder, Decodable, Encoder, Encodable};
use session::{config, early_error, Session};
use traits::Reveal;
use ty::{self, TyCtxt};
use ty::{self, TyCtxt, Ty};
use ty::layout::{LayoutError, LayoutOf, TyLayout};
use util::nodemap::FxHashMap;

use std::default::Default as StdDefault;
Expand Down Expand Up @@ -623,6 +624,14 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> {
}
}

impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for &'a LateContext<'a, 'tcx> {
type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;

fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
(self.tcx, self.param_env.reveal_all()).layout_of(ty)
}
}

impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
/// Because lints are scoped lexically, we want to walk nested
/// items in the context of the outer item, so enable
Expand Down
8 changes: 4 additions & 4 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ use ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate, Predic
use ty::RegionKind;
use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
use ty::TypeVariants::*;
use ty::layout::{Layout, TargetDataLayout};
use ty::layout::{LayoutDetails, TargetDataLayout};
use ty::maps;
use ty::steal::Steal;
use ty::BindingMode;
Expand Down Expand Up @@ -79,7 +79,7 @@ use hir;
/// Internal storage
pub struct GlobalArenas<'tcx> {
// internings
layout: TypedArena<Layout>,
layout: TypedArena<LayoutDetails>,

// references
generics: TypedArena<ty::Generics>,
Expand Down Expand Up @@ -916,7 +916,7 @@ pub struct GlobalCtxt<'tcx> {

stability_interner: RefCell<FxHashSet<&'tcx attr::Stability>>,

layout_interner: RefCell<FxHashSet<&'tcx Layout>>,
layout_interner: RefCell<FxHashSet<&'tcx LayoutDetails>>,

/// A vector of every trait accessible in the whole crate
/// (i.e. including those from subcrates). This is used only for
Expand Down Expand Up @@ -1014,7 +1014,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
interned
}

pub fn intern_layout(self, layout: Layout) -> &'gcx Layout {
pub fn intern_layout(self, layout: LayoutDetails) -> &'gcx LayoutDetails {
if let Some(layout) = self.layout_interner.borrow().get(&layout) {
return layout;
}
Expand Down
Loading

0 comments on commit fa5efe4

Please sign in to comment.