Add align_offset intrinsic
see https://github.com/rust-lang/rfcs/pull/2043 for details
This commit is contained in:
parent
1b08e0f231
commit
1dc3a2b5fa
@ -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;
|
||||
/// *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;
|
||||
/// *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
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ use fmt;
|
||||
use iter::{Map, Cloned, FusedIterator};
|
||||
use slice::{self, SliceIndex};
|
||||
use mem;
|
||||
use intrinsics::align_offset;
|
||||
|
||||
pub mod pattern;
|
||||
|
||||
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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: `{}`",
|
||||
|
Loading…
Reference in New Issue
Block a user