Skip to content

Commit

Permalink
Auto merge of #43903 - oli-obk:alignto, r=aturon
Browse files Browse the repository at this point in the history
Add align_offset intrinsic

see rust-lang/rfcs#2043 for details and the plan towards stabilization (reexport in `core::mem` via various convenience functions)

as per @scottmcm 's [comment](rust-lang/rfcs#2043 (comment)), this is just the intrinsic (which is obviously unstable).
  • Loading branch information
bors committed Aug 30, 2017
2 parents b58e31a + be96ad2 commit c66e7fa
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 1 deletion.
77 changes: 77 additions & 0 deletions src/libcore/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1343,4 +1343,81 @@ extern "rust-intrinsic" {
/// on MSVC it's `*mut [usize; 2]`. For more information see the compiler's
/// source as well as std's catch implementation.
pub fn try(f: fn(*mut u8), data: *mut u8, local_ptr: *mut u8) -> i32;

/// Computes the byte offset that needs to be applied to `ptr` in order to
/// make it aligned to `align`.
/// If it is not possible to align `ptr`, the implementation returns
/// `usize::max_value()`.
///
/// There are no guarantees whatsover that offsetting the pointer will not
/// overflow or go beyond the allocation that `ptr` points into.
/// It is up to the caller to ensure that the returned offset is correct
/// in all terms other than alignment.
///
/// # Examples
///
/// Accessing adjacent `u8` as `u16`
///
/// ```
/// # #![feature(core_intrinsics)]
/// # fn foo(n: usize) {
/// # use std::intrinsics::align_offset;
/// # use std::mem::align_of;
/// # unsafe {
/// let x = [5u8, 6u8, 7u8, 8u8, 9u8];
/// let ptr = &x[n] as *const u8;
/// let offset = align_offset(ptr as *const (), align_of::<u16>());
/// if offset < x.len() - n - 1 {
/// let u16_ptr = ptr.offset(offset as isize) as *const u16;
/// assert_ne!(*u16_ptr, 500);
/// } else {
/// // while the pointer can be aligned via `offset`, it would point
/// // outside the allocation
/// }
/// # } }
/// ```
#[cfg(not(stage0))]
pub fn align_offset(ptr: *const (), align: usize) -> usize;
}

#[cfg(stage0)]
/// Computes the byte offset that needs to be applied to `ptr` in order to
/// make it aligned to `align`.
/// If it is not possible to align `ptr`, the implementation returns
/// `usize::max_value()`.
///
/// There are no guarantees whatsover that offsetting the pointer will not
/// overflow or go beyond the allocation that `ptr` points into.
/// It is up to the caller to ensure that the returned offset is correct
/// in all terms other than alignment.
///
/// # Examples
///
/// Accessing adjacent `u8` as `u16`
///
/// ```
/// # #![feature(core_intrinsics)]
/// # fn foo(n: usize) {
/// # use std::intrinsics::align_offset;
/// # use std::mem::align_of;
/// # unsafe {
/// let x = [5u8, 6u8, 7u8, 8u8, 9u8];
/// let ptr = &x[n] as *const u8;
/// let offset = align_offset(ptr as *const (), align_of::<u16>());
/// if offset < x.len() - n - 1 {
/// let u16_ptr = ptr.offset(offset as isize) as *const u16;
/// assert_ne!(*u16_ptr, 500);
/// } else {
/// // while the pointer can be aligned via `offset`, it would point
/// // outside the allocation
/// }
/// # } }
/// ```
pub unsafe fn align_offset(ptr: *const (), align: usize) -> usize {
let offset = ptr as usize % align;
if offset == 0 {
0
} else {
align - offset
}
}
6 changes: 5 additions & 1 deletion src/libcore/str/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use fmt;
use iter::{Map, Cloned, FusedIterator};
use slice::{self, SliceIndex};
use mem;
use intrinsics::align_offset;

pub mod pattern;

Expand Down Expand Up @@ -1468,7 +1469,10 @@ fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
// When the pointer is aligned, read 2 words of data per iteration
// until we find a word containing a non-ascii byte.
let ptr = v.as_ptr();
let align = (ptr as usize + index) & (usize_bytes - 1);
let align = unsafe {
// the offset is safe, because `index` is guaranteed inbounds
align_offset(ptr.offset(index as isize) as *const (), usize_bytes)
};
if align == 0 {
while index < blocks_end {
unsafe {
Expand Down
12 changes: 12 additions & 0 deletions src/librustc_trans/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,18 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
_ => C_null(llret_ty)
}
}

"align_offset" => {
// `ptr as usize`
let ptr_val = bcx.ptrtoint(llargs[0], bcx.ccx.int_type());
// `ptr_val % align`
let offset = bcx.urem(ptr_val, llargs[1]);
let zero = C_null(bcx.ccx.int_type());
// `offset == 0`
let is_zero = bcx.icmp(llvm::IntPredicate::IntEQ, offset, zero);
// `if offset == 0 { 0 } else { offset - align }`
bcx.select(is_zero, zero, bcx.sub(offset, llargs[1]))
}
name if name.starts_with("simd_") => {
generic_simd_intrinsic(bcx, name,
callee_ty,
Expand Down
5 changes: 5 additions & 0 deletions src/librustc_typeck/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,11 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
(0, vec![tcx.mk_fn_ptr(fn_ty), mut_u8, mut_u8], tcx.types.i32)
}

"align_offset" => {
let ptr_ty = tcx.mk_imm_ptr(tcx.mk_nil());
(0, vec![ptr_ty, tcx.types.usize], tcx.types.usize)
},

ref other => {
struct_span_err!(tcx.sess, it.span, E0093,
"unrecognized intrinsic function: `{}`",
Expand Down

0 comments on commit c66e7fa

Please sign in to comment.