]> git.lizzy.rs Git - rust.git/commitdiff
Add align_offset intrinsic
authorOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>
Wed, 16 Aug 2017 13:41:09 +0000 (15:41 +0200)
committerOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>
Mon, 21 Aug 2017 13:57:21 +0000 (15:57 +0200)
see https://github.com/rust-lang/rfcs/pull/2043 for details

src/libcore/intrinsics.rs
src/libcore/str/mod.rs
src/librustc_trans/intrinsic.rs
src/librustc_typeck/check/intrinsic.rs

index ad776c8605ac83cef3dec2ce8194603fa6f1a5f8..d87b0475e0c3acffaf0ca1928f27ef6a50de8420 100644 (file)
@@ -1343,4 +1343,81 @@ pub fn volatile_copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T,
     /// 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
+    }
 }
index 4c99fe97dafa38a73d64cfddd626ef583675d087..ed399bef44926396b9f8b0c25f3bf11d8a70622f 100644 (file)
@@ -23,6 +23,7 @@
 use iter::{Map, Cloned, FusedIterator};
 use slice::{self, SliceIndex};
 use mem;
+use intrinsics::align_offset;
 
 pub mod pattern;
 
@@ -1468,7 +1469,10 @@ macro_rules! next { () => {{
             // 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 {
index 033ef988571dd263a5ad4c82161a3a522b89b2a3..9a3c8a5079a2f2b9c8dc6f42089f0f6b2b36f745 100644 (file)
@@ -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,
index 96643ae72abadc5c7beaade2ff465137743c0a17..6fee7e58633fcf12e560c189f648b324e192b978 100644 (file)
@@ -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: `{}`",