Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add {size/min_align/pref_align}_of_val intrinsic #21587

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/libcore/intrinsics.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
Expand Down Expand Up @@ -187,14 +187,21 @@ extern "rust-intrinsic" {
/// and structures there may be additional padding between
/// elements.
pub fn size_of<T>() -> uint;
#[cfg(not(stage0))]
pub fn size_of_val<T: ?Sized>(val: &T) -> uint;

/// Move a value to an uninitialized memory location.
///
/// Drop glue is not run on the destination.
pub fn move_val_init<T>(dst: &mut T, src: T);

pub fn min_align_of<T>() -> uint;
#[cfg(not(stage0))]
pub fn min_align_of_val<T: ?Sized>(val: &T) -> uint;

pub fn pref_align_of<T>() -> uint;
#[cfg(not(stage0))]
pub fn pref_align_of_val<T: ?Sized>(val: &T) -> uint;

/// Get a static pointer to a type descriptor.
#[cfg(not(stage0))]
Expand Down
58 changes: 56 additions & 2 deletions src/libcore/mem.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
Expand Down Expand Up @@ -47,6 +47,22 @@ pub fn size_of<T>() -> uint {
unsafe { intrinsics::size_of::<T>() }
}

/// Returns the size of the type that `val` points to in bytes.
///
/// # Examples
///
/// ```
/// use std::mem;
///
/// assert_eq!(4, mem::size_of_val(&5i32));
/// ```
#[inline]
#[stable]
#[cfg(not(stage0))]
pub fn size_of_val<T: ?Sized>(val: &T) -> uint {
unsafe { intrinsics::size_of_val(val) }
}

/// Returns the size of the type that `_val` points to in bytes.
///
/// # Examples
Expand All @@ -58,6 +74,7 @@ pub fn size_of<T>() -> uint {
/// ```
#[inline]
#[stable]
#[cfg(stage0)]
pub fn size_of_val<T>(_val: &T) -> uint {
size_of::<T>()
}
Expand All @@ -79,7 +96,7 @@ pub fn min_align_of<T>() -> uint {
unsafe { intrinsics::min_align_of::<T>() }
}

/// Returns the ABI-required minimum alignment of the type of the value that `_val` points to
/// Returns the ABI-required minimum alignment of the type of the value that `val` points to.
///
/// # Examples
///
Expand All @@ -90,6 +107,23 @@ pub fn min_align_of<T>() -> uint {
/// ```
#[inline]
#[stable]
#[cfg(not(stage0))]
pub fn min_align_of_val<T: ?Sized>(val: &T) -> uint {
unsafe { intrinsics::min_align_of_val(val) }
}

/// Returns the ABI-required minimum alignment of the type of the value that `_val` points to.
///
/// # Examples
///
/// ```
/// use std::mem;
///
/// assert_eq!(4, mem::min_align_of_val(&5i32));
/// ```
#[inline]
#[stable]
#[cfg(stage0)]
pub fn min_align_of_val<T>(_val: &T) -> uint {
min_align_of::<T>()
}
Expand All @@ -116,6 +150,25 @@ pub fn align_of<T>() -> uint {
unsafe { intrinsics::pref_align_of::<T>() }
}

/// Returns the alignment of the type of the value that `val` points to.
///
/// This is similar to `align_of`, but can handle types such as trait object, returning the
/// alignment for an arbitrary value at runtime.
///
/// # Examples
///
/// ```
/// use std::mem;
///
/// assert_eq!(4, mem::align_of_val(&5i32));
/// ```
#[inline]
#[stable]
#[cfg(not(stage0))]
pub fn align_of_val<T: ?Sized>(val: &T) -> uint {
unsafe { intrinsics::pref_align_of_val(val) }
}

/// Returns the alignment of the type of the value that `_val` points to.
///
/// This is similar to `align_of`, but function will properly handle types such as trait objects
Expand All @@ -130,6 +183,7 @@ pub fn align_of<T>() -> uint {
/// ```
#[inline]
#[stable]
#[cfg(stage0)]
pub fn align_of_val<T>(_val: &T) -> uint {
align_of::<T>()
}
Expand Down
33 changes: 19 additions & 14 deletions src/librustc_trans/trans/glue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,38 +297,42 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
})
}

fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info: ValueRef)
pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>,
info: ValueRef, align: AlignType)
-> (ValueRef, ValueRef) {
debug!("calculate size of DST: {}; with lost info: {}",
bcx.ty_to_string(t), bcx.val_to_string(info));
if type_is_sized(bcx.tcx(), t) {
let sizing_type = sizing_type_of(bcx.ccx(), t);
let size = C_uint(bcx.ccx(), llsize_of_alloc(bcx.ccx(), sizing_type));
let align = C_uint(bcx.ccx(), align_of(bcx.ccx(), t));
let align = C_uint(bcx.ccx(), align.align_of(bcx.ccx(), sizing_type));
return (size, align);
}
match t.sty {
ty::ty_struct(id, substs) => {
let ccx = bcx.ccx();
// First get the size of all statically known fields.
// Don't use type_of::sizing_type_of because that expects t to be sized.
assert!(!ty::type_is_simd(bcx.tcx(), t));
let repr = adt::represent_type(ccx, t);
let sizing_type = adt::sizing_type_of(ccx, &*repr, true);
let sized_size = C_uint(ccx, llsize_of_alloc(ccx, sizing_type));
let sized_align = C_uint(ccx, llalign_of_min(ccx, sizing_type));

// Recurse to get the size of the dynamically sized field (must be
// the last field).
let fields = ty::struct_fields(bcx.tcx(), id, substs);
let last_field = fields[fields.len()-1];
let field_ty = last_field.mt.ty;
let (unsized_size, unsized_align) = size_and_align_of_dst(bcx, field_ty, info);
let (unsized_size, unsized_align) = size_and_align_of_dst(bcx, field_ty,
info, align);

// First get the size of all statically known fields.
// Don't use type_of::sizing_type_of because that expects t to be sized.
assert!(!ty::type_is_simd(bcx.tcx(), t));
let repr = adt::represent_type(ccx, t);
let sizing_type = adt::sizing_type_of(ccx, &*repr, true);
let dst_type = type_of(ccx, t);
let sized_size = C_uint(ccx, llelement_offset(ccx, dst_type,
fields.len() - 1));
let sized_align = C_uint(ccx, align.align_of(ccx, sizing_type));

// Return the sum of sizes and max of aligns.
let size = Add(bcx, sized_size, unsized_size, DebugLoc::None);
let align = Select(bcx,
ICmp(bcx, llvm::IntULT, sized_align, unsized_align),
ICmp(bcx, llvm::IntUGE, sized_align, unsized_align),
sized_align,
unsized_align);
(size, align)
Expand All @@ -346,7 +350,7 @@ fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info:
// The info in this case is the length of the str, so the size is that
// times the unit size.
let llunit_ty = sizing_type_of(bcx.ccx(), unit_ty);
let unit_align = llalign_of_min(bcx.ccx(), llunit_ty);
let unit_align = align.align_of(bcx.ccx(), llunit_ty);
let unit_size = llsize_of_alloc(bcx.ccx(), llunit_ty);
(Mul(bcx, info, C_uint(bcx.ccx(), unit_size), DebugLoc::None),
C_uint(bcx.ccx(), unit_align))
Expand Down Expand Up @@ -393,7 +397,8 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
let bcx = drop_ty(bcx, v0, content_ty, DebugLoc::None);
let info = GEPi(bcx, v0, &[0, abi::FAT_PTR_EXTRA]);
let info = Load(bcx, info);
let (llsize, llalign) = size_and_align_of_dst(bcx, content_ty, info);
let (llsize, llalign) = size_and_align_of_dst(bcx, content_ty,
info, AlignType::Min);
trans_exchange_free_dyn(bcx, llbox, llsize, llalign)
})
}
Expand Down
59 changes: 53 additions & 6 deletions src/librustc_trans/trans/intrinsic.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
Expand All @@ -10,6 +10,7 @@

#![allow(non_upper_case_globals)]

use back::abi;
use llvm;
use llvm::{SequentiallyConsistent, Acquire, Release, AtomicXchg, ValueRef, TypeKind};
use middle::subst;
Expand Down Expand Up @@ -314,17 +315,62 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
}
(_, "size_of") => {
let tp_ty = *substs.types.get(FnSpace, 0);
let lltp_ty = type_of::type_of(ccx, tp_ty);
C_uint(ccx, machine::llsize_of_alloc(ccx, lltp_ty))
let llty = type_of::sizing_type_of(ccx, tp_ty);
C_uint(ccx, machine::llsize_of_alloc(ccx, llty))
}
(_, "min_align_of") => {
let tp_ty = *substs.types.get(FnSpace, 0);
C_uint(ccx, type_of::align_of(ccx, tp_ty))
let llty = type_of::sizing_type_of(ccx, tp_ty);
C_uint(ccx, machine::llalign_of_min(ccx, llty))
}
(_, "pref_align_of") => {
let tp_ty = *substs.types.get(FnSpace, 0);
let lltp_ty = type_of::type_of(ccx, tp_ty);
C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty))
let llty = type_of::sizing_type_of(ccx, tp_ty);
C_uint(ccx, machine::llalign_of_pref(ccx, llty))
}
(_, "size_of_val") => {
let tp_ty = *substs.types.get(FnSpace, 0);
if type_is_sized(tcx, tp_ty) {
let llty = type_of::sizing_type_of(ccx, tp_ty);
C_uint(ccx, machine::llsize_of_alloc(ccx, llty))
} else {
let ptr = GEPi(bcx, llargs[0], &[0, abi::FAT_PTR_EXTRA]);
let (size, align) = glue::size_and_align_of_dst(bcx, tp_ty,
Load(bcx, ptr), machine::AlignType::Min);

// If the size is not aligned to the alignment, then we need to
// round it up to the next number which matches the alignment
let rem = URem(bcx, size, align, call_debug_location);
Select(bcx,
ICmp(bcx, llvm::IntPredicate::IntEQ, rem, C_uint(ccx, 0u64)),
size,
Add(bcx, size, Sub(bcx, align, rem, call_debug_location),
call_debug_location))
}
}
(_, "min_align_of_val") => {
let tp_ty = *substs.types.get(FnSpace, 0);
if type_is_sized(tcx, tp_ty) {
let llty = type_of::sizing_type_of(ccx, tp_ty);
C_uint(ccx, machine::llalign_of_min(ccx, llty))
} else {
let ptr = GEPi(bcx, llargs[0], &[0, abi::FAT_PTR_EXTRA]);
let (_, align) = glue::size_and_align_of_dst(bcx, tp_ty,
Load(bcx, ptr), machine::AlignType::Min);
align
}
}
(_, "pref_align_of_val") => {
let tp_ty = *substs.types.get(FnSpace, 0);
if type_is_sized(tcx, tp_ty) {
let llty = type_of::sizing_type_of(ccx, tp_ty);
C_uint(ccx, machine::llalign_of_pref(ccx, llty))
} else {
let ptr = GEPi(bcx, llargs[0], &[0, abi::FAT_PTR_EXTRA]);
let (_, align) = glue::size_and_align_of_dst(bcx, tp_ty,
Load(bcx, ptr), machine::AlignType::Pref);
align
}
}
(_, "move_val_init") => {
// Create a datum reflecting the value being moved.
Expand Down Expand Up @@ -877,3 +923,4 @@ fn with_overflow_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
ret
}
}

15 changes: 15 additions & 0 deletions src/librustc_trans/trans/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,21 @@ pub fn llsize_of(cx: &CrateContext, ty: Type) -> ValueRef {
return C_uint(cx, llsize_of_alloc(cx, ty));
}

#[derive(Copy)]
pub enum AlignType {
Min,
Pref
}
impl AlignType {
pub fn align_of<'a, 'tcx>(&self, ccx: &CrateContext<'a, 'tcx>,
ty: Type) -> llalign {
match *self {
AlignType::Min => llalign_of_min(ccx, ty),
AlignType::Pref => llalign_of_pref(ccx, ty)
}
}
}

// Returns the preferred alignment of the given type for the current target.
// The preferred alignment may be larger than the alignment used when
// packing the type into structs. This will be used for things like
Expand Down
7 changes: 7 additions & 0 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5243,6 +5243,13 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
"breakpoint" => (0, Vec::new(), ty::mk_nil(tcx)),
"size_of" |
"pref_align_of" | "min_align_of" => (1u, Vec::new(), ccx.tcx.types.uint),
"size_of_val" | "min_align_of_val" |
"pref_align_of_val" => (1u,
vec!(ty::mk_imm_rptr(tcx,
tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1),
ty::BrAnon(0))),
param(ccx, 0))),
ccx.tcx.types.uint),
"init" => (1u, Vec::new(), param(ccx, 0)),
"uninit" => (1u, Vec::new(), param(ccx, 0)),
"forget" => (1u, vec!( param(ccx, 0) ), ty::mk_nil(tcx)),
Expand Down
Loading