From b7266c6008ea2497da20d92d0c49ccc16bd8a699 Mon Sep 17 00:00:00 2001 From: Daan de Graaf Date: Mon, 24 Dec 2018 17:52:50 +0100 Subject: [PATCH] Move pointee_info_at to TyLayoutMethods. The original implementation is still present at librustc_codegen_llvm/abi.rs, should be removed later to prevent code duplication. --- src/librustc/ty/layout.rs | 127 +++++++++++++++++++++++++++++++++ src/librustc_target/abi/mod.rs | 27 +++++++ 2 files changed, 154 insertions(+) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 21e4d8b07a19..a67aa0e41b37 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -12,6 +12,7 @@ use std::iter; use std::mem; use std::ops::Bound; +use hir; use crate::ich::StableHashingContext; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, @@ -1545,6 +1546,7 @@ impl<'gcx, 'tcx, T: HasTyCtxt<'gcx>> HasTyCtxt<'gcx> for LayoutCx<'tcx, T> { pub trait MaybeResult { fn from_ok(x: T) -> Self; fn map_same T>(self, f: F) -> Self; + fn ok(self) -> Option; } impl MaybeResult for T { @@ -1554,6 +1556,9 @@ impl MaybeResult for T { fn map_same T>(self, f: F) -> Self { f(self) } + fn ok(self) -> Option { + Some(self) + } } impl MaybeResult for Result { @@ -1563,6 +1568,9 @@ impl MaybeResult for Result { fn map_same T>(self, f: F) -> Self { self.map(f) } + fn ok(self) -> Option { + self.ok() + } } pub type TyLayout<'tcx> = ::rustc_target::abi::TyLayout<'tcx, Ty<'tcx>>; @@ -1824,6 +1832,125 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> } }) } + + fn pointee_info_at(this: TyLayout<'tcx>, cx: &C, offset: Size + ) -> Option { + let mut result = None; + match this.ty.sty { + ty::RawPtr(mt) if offset.bytes() == 0 => { + result = cx.layout_of(mt.ty).ok() + .map(|layout| PointeeInfo { + size: layout.size, + align: layout.align.abi, + safe: None, + }); + } + + ty::Ref(_, ty, mt) if offset.bytes() == 0 => { + let tcx = cx.tcx(); + let is_freeze = ty.is_freeze(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP); + let kind = match mt { + hir::MutImmutable => if is_freeze { + PointerKind::Frozen + } else { + PointerKind::Shared + }, + hir::MutMutable => { + // Previously we would only emit noalias annotations for LLVM >= 6 or in + // panic=abort mode. That was deemed right, as prior versions had many bugs + // in conjunction with unwinding, but later versions didn’t seem to have + // said issues. See issue #31681. + // + // Alas, later on we encountered a case where noalias would generate wrong + // code altogether even with recent versions of LLVM in *safe* code with no + // unwinding involved. See #54462. + // + // For now, do not enable mutable_noalias by default at all, while the + // issue is being figured out. + let mutable_noalias = tcx.sess.opts.debugging_opts.mutable_noalias + .unwrap_or(false); + if mutable_noalias { + PointerKind::UniqueBorrowed + } else { + PointerKind::Shared + } + } + }; + + result = cx.layout_of(ty).ok() + .map(|layout| PointeeInfo { + size: layout.size, + align: layout.align.abi, + safe: Some(kind), + }); + } + + _ => { + let mut data_variant = match this.variants { + Variants::NicheFilling { dataful_variant, .. } => { + // Only the niche itthis is always initialized, + // so only check for a pointer at its offset. + // + // If the niche is a pointer, it's either valid + // (according to its type), or null (which the + // niche field's scalar validity range encodes). + // This allows using `dereferenceable_or_null` + // for e.g., `Option<&T>`, and this will continue + // to work as long as we don't start using more + // niches than just null (e.g., the first page + // of the address space, or unaligned pointers). + if this.fields.offset(0) == offset { + Some(this.for_variant(cx, dataful_variant)) + } else { + None + } + } + _ => Some(this) + }; + + if let Some(variant) = data_variant { + // We're not interested in any unions. + if let FieldPlacement::Union(_) = variant.fields { + data_variant = None; + } + } + + if let Some(variant) = data_variant { + let ptr_end = offset + Pointer.size(cx); + for i in 0..variant.fields.count() { + let field_start = variant.fields.offset(i); + if field_start <= offset { + let field = variant.field(cx, i); + result = field.ok() + .and_then(|field| { + if ptr_end <= field_start + field.size { + // We found the right field, look inside it. + Self::pointee_info_at(field, cx, offset - field_start) + } else { + None + } + }); + if result.is_some() { + break; + } + } + } + } + + // FIXME(eddyb) This should be for `ptr::Unique`, not `Box`. + if let Some(ref mut pointee) = result { + if let ty::Adt(def, _) = this.ty.sty { + if def.is_box() && offset.bytes() == 0 { + pointee.safe = Some(PointerKind::UniqueOwned); + } + } + } + } + } + + result + } + } struct Niche { diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 59eda97a2f9f..74257cb3f648 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -910,6 +910,28 @@ pub trait LayoutOf { fn layout_of(&self, ty: Self::Ty) -> Self::TyLayout; } +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum PointerKind { + /// Most general case, we know no restrictions to tell LLVM. + Shared, + + /// `&T` where `T` contains no `UnsafeCell`, is `noalias` and `readonly`. + Frozen, + + /// `&mut T`, when we know `noalias` is safe for LLVM. + UniqueBorrowed, + + /// `Box`, unlike `UniqueBorrowed`, it also has `noalias` on returns. + UniqueOwned +} + +#[derive(Copy, Clone)] +pub struct PointeeInfo { + pub size: Size, + pub align: Align, + pub safe: Option, +} + pub trait TyLayoutMethods<'a, C: LayoutOf>: Sized { fn for_variant( this: TyLayout<'a, Self>, @@ -917,6 +939,11 @@ pub trait TyLayoutMethods<'a, C: LayoutOf>: Sized { variant_index: VariantIdx, ) -> TyLayout<'a, Self>; fn field(this: TyLayout<'a, Self>, cx: &C, i: usize) -> C::TyLayout; + fn pointee_info_at( + this: TyLayout<'a, Self>, + cx: &C, + offset: Size + ) -> Option; } impl<'a, Ty> TyLayout<'a, Ty> {