From 6d5bf8b23f4e59fdc67f635a10f450dfab2f076b Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 4 May 2018 00:49:22 +0300 Subject: Remove the intrinsic for align_offset Keep only the language item. This removes some indirection and makes codegen worse for debug builds, but simplifies code significantly, which is a good tradeoff to make, in my opinion. Besides, the codegen can be improved even further with some constant evaluation improvements that we expect to happen in the future. --- src/libcore/intrinsics.rs | 42 ------------------------------------------ src/libcore/ptr.rs | 31 +++++++++++++++++++++---------- src/libcore/slice/mod.rs | 7 +++++-- 3 files changed, 26 insertions(+), 54 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 510a5bb3df7..1420e00b47f 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1467,48 +1467,6 @@ extern "rust-intrinsic" { /// docs my friends, its friday! pub fn align_offset(ptr: *const (), align: usize) -> usize; - /// Computes the offset that needs to be applied to the pointer in order to make it aligned to - /// `align`. - /// - /// If it is not possible to align the pointer, the implementation returns - /// `usize::max_value()`. - /// - /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be - /// used with the `offset` or `offset_to` methods. - /// - /// There are no guarantees whatsover that offsetting the pointer will not overflow or go - /// beyond the allocation that the pointer points into. It is up to the caller to ensure that - /// the returned offset is correct in all terms other than alignment. - /// - /// # Unsafety - /// - /// `align` must be a power-of-two. - /// - /// # 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, align_of::()); - /// 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 T, align: usize) -> usize; - /// Emits a `!nontemporal` store according to LLVM (see their docs). /// Probably will never become stable. pub fn nontemporal_store(ptr: *mut T, val: T); diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index a762a8a6f92..e2286d23e33 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -1478,7 +1478,7 @@ impl *const T { panic!("align_offset: align is not a power-of-two"); } unsafe { - intrinsics::align_offset(self, align) + align_offset(self, align) } } @@ -2543,7 +2543,7 @@ impl *mut T { panic!("align_offset: align is not a power-of-two"); } unsafe { - intrinsics::align_offset(self, align) + align_offset(self, align) } } @@ -2565,8 +2565,6 @@ impl *mut T { /// Calculate offset (in terms of elements of `stride` stride) that has to be applied /// to pointer `p` so that pointer `p` would get aligned to `a`. /// -/// This is an implementation of the `align_offset` intrinsic for the case where `stride > 1`. -/// /// Note: This implementation has been carefully tailored to not panic. It is UB for this to panic. /// The only real change that can be made here is change of `INV_TABLE_MOD_16` and associated /// constants. @@ -2578,7 +2576,7 @@ impl *mut T { /// Any questions go to @nagisa. #[lang="align_offset"] #[cfg(not(stage0))] -unsafe fn align_offset(p: *const (), a: usize, stride: usize) -> usize { +pub(crate) unsafe fn align_offset(p: *const T, a: usize) -> usize { /// Calculate multiplicative modular inverse of `x` modulo `m`. /// /// This implementation is tailored for align_offset and has following preconditions: @@ -2587,12 +2585,13 @@ unsafe fn align_offset(p: *const (), a: usize, stride: usize) -> usize { /// * `x < m`; (if `x ≥ m`, pass in `x % m` instead) /// /// Implementation of this function shall not panic. Ever. + #[inline] fn mod_inv(x: usize, m: usize) -> usize { /// Multiplicative modular inverse table modulo 2⁴ = 16. /// /// Note, that this table does not contain values where inverse does not exist (i.e. for /// `0⁻¹ mod 16`, `2⁻¹ mod 16`, etc.) - static INV_TABLE_MOD_16: [usize; 8] = [1, 11, 13, 7, 9, 3, 5, 15]; + const INV_TABLE_MOD_16: [usize; 8] = [1, 11, 13, 7, 9, 3, 5, 15]; /// Modulo for which the `INV_TABLE_MOD_16` is intended. const INV_TABLE_MOD: usize = 16; /// INV_TABLE_MOD² @@ -2627,18 +2626,30 @@ unsafe fn align_offset(p: *const (), a: usize, stride: usize) -> usize { } } + let stride = ::mem::size_of::(); let a_minus_one = a.wrapping_sub(1); let pmoda = p as usize & a_minus_one; - let smoda = stride & a_minus_one; - // a is power-of-two so cannot be 0. stride = 0 is handled by the intrinsic. - let gcdpow = intrinsics::cttz_nonzero(stride).min(intrinsics::cttz_nonzero(a)); - let gcd = 1usize << gcdpow; if pmoda == 0 { // Already aligned. Yay! return 0; } + if stride <= 1 { + return if stride == 0 { + // If the pointer is not aligned, and the element is zero-sized, then no amount of + // elements will ever align the pointer. + !0 + } else { + a.wrapping_sub(pmoda) + }; + } + + let smoda = stride & a_minus_one; + // a is power-of-two so cannot be 0. stride = 0 is handled above. + let gcdpow = intrinsics::cttz_nonzero(stride).min(intrinsics::cttz_nonzero(a)); + let gcd = 1usize << gcdpow; + if gcd == 1 { // This branch solves for the variable $o$ in following linear congruence equation: // diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index ffa4a66346c..fdc9aa473e8 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1794,8 +1794,11 @@ impl [T] { // handle ZSTs specially, which is – don't handle them at all. return (self, &[], &[]); } + + // First, find at what point do we split between the first and 2nd slice. Easy with + // ptr.align_offset. let ptr = self.as_ptr(); - let offset = ::intrinsics::align_offset(ptr, ::mem::align_of::()); + let offset = ::ptr::align_offset(ptr, ::mem::align_of::()); if offset > self.len() { return (self, &[], &[]); } else { @@ -1848,7 +1851,7 @@ impl [T] { // First, find at what point do we split between the first and 2nd slice. Easy with // ptr.align_offset. let ptr = self.as_ptr(); - let offset = ::intrinsics::align_offset(ptr, ::mem::align_of::()); + let offset = ::ptr::align_offset(ptr, ::mem::align_of::()); if offset > self.len() { return (self, &mut [], &mut []); } else { -- cgit 1.4.1-3-g733a5