always use align_offset
in is_aligned_to
+ add assembly test
This commit is contained in:
parent
4696e8906d
commit
daccb8c11a
@ -1321,6 +1321,7 @@ pub unsafe fn read_volatile(self) -> T
|
||||
/// # }
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[inline]
|
||||
#[stable(feature = "align_offset", since = "1.36.0")]
|
||||
#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")]
|
||||
pub const fn align_offset(self, align: usize) -> usize
|
||||
@ -1562,19 +1563,11 @@ pub const fn is_aligned_to(self, align: usize) -> bool {
|
||||
panic!("is_aligned_to: align is not a power-of-two")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn runtime(ptr: *const u8, align: usize) -> bool {
|
||||
ptr.addr() & (align - 1) == 0
|
||||
}
|
||||
|
||||
// This optimizes to `(ptr + align - 1) & -align == ptr`, which is slightly
|
||||
// slower than `ptr & (align - 1) == 0`
|
||||
const fn comptime(ptr: *const u8, align: usize) -> bool {
|
||||
ptr.align_offset(align) == 0
|
||||
}
|
||||
|
||||
// SAFETY: `ptr.align_offset(align)` returns 0 if and only if the pointer is already aligned.
|
||||
unsafe { intrinsics::const_eval_select((self.cast::<u8>(), align), comptime, runtime) }
|
||||
// We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
|
||||
// The cast to `()` is used to
|
||||
// 1. deal with fat pointers; and
|
||||
// 2. ensure that `align_offset` doesn't actually try to compute an offset.
|
||||
self.cast::<()>().align_offset(align) == 0
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1589,6 +1589,7 @@ pub unsafe fn replace(self, src: T) -> T
|
||||
/// # }
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[inline]
|
||||
#[stable(feature = "align_offset", since = "1.36.0")]
|
||||
#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")]
|
||||
pub const fn align_offset(self, align: usize) -> usize
|
||||
@ -1830,19 +1831,11 @@ pub const fn is_aligned_to(self, align: usize) -> bool {
|
||||
panic!("is_aligned_to: align is not a power-of-two")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn runtime(ptr: *mut u8, align: usize) -> bool {
|
||||
ptr.addr() & (align - 1) == 0
|
||||
}
|
||||
|
||||
// This optimizes to `(ptr + align - 1) & -align == ptr`, which is slightly
|
||||
// slower than `ptr & (align - 1) == 0`
|
||||
const fn comptime(ptr: *mut u8, align: usize) -> bool {
|
||||
ptr.align_offset(align) == 0
|
||||
}
|
||||
|
||||
// SAFETY: `ptr.align_offset(align)` returns 0 if and only if the pointer is already aligned.
|
||||
unsafe { intrinsics::const_eval_select((self.cast::<u8>(), align), comptime, runtime) }
|
||||
// We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
|
||||
// The cast to `()` is used to
|
||||
// 1. deal with fat pointers; and
|
||||
// 2. ensure that `align_offset` doesn't actually try to compute an offset.
|
||||
self.cast::<()>().align_offset(align) == 0
|
||||
}
|
||||
}
|
||||
|
||||
|
58
src/test/assembly/is_aligned.rs
Normal file
58
src/test/assembly/is_aligned.rs
Normal file
@ -0,0 +1,58 @@
|
||||
// assembly-output: emit-asm
|
||||
// min-llvm-version: 14.0
|
||||
// only-x86_64
|
||||
// revisions: opt-speed opt-size
|
||||
// [opt-speed] compile-flags: -Copt-level=1
|
||||
// [opt-size] compile-flags: -Copt-level=s
|
||||
#![crate_type="rlib"]
|
||||
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(pointer_is_aligned)]
|
||||
|
||||
// CHECK-LABEL: is_aligned_to_unchecked
|
||||
// CHECK: decq %rsi
|
||||
// CHECK-NEXT: testq %rdi, %rsi
|
||||
// CHECK-NEXT: sete %al
|
||||
// CHECK-NEXT: retq
|
||||
#[no_mangle]
|
||||
pub unsafe fn is_aligned_to_unchecked(ptr: *const u8, align: usize) -> bool {
|
||||
unsafe {
|
||||
std::intrinsics::assume(align.is_power_of_two())
|
||||
}
|
||||
ptr.is_aligned_to(align)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: is_aligned_1
|
||||
// CHECK: movb $1, %al
|
||||
// CHECK-NEXT: retq
|
||||
#[no_mangle]
|
||||
pub fn is_aligned_1(ptr: *const u8) -> bool {
|
||||
ptr.is_aligned()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: is_aligned_2
|
||||
// CHECK: testb $1, %dil
|
||||
// CHECK-NEXT: sete %al
|
||||
// CHECK-NEXT: retq
|
||||
#[no_mangle]
|
||||
pub fn is_aligned_2(ptr: *const u16) -> bool {
|
||||
ptr.is_aligned()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: is_aligned_4
|
||||
// CHECK: testb $3, %dil
|
||||
// CHECK-NEXT: sete %al
|
||||
// CHECK-NEXT: retq
|
||||
#[no_mangle]
|
||||
pub fn is_aligned_4(ptr: *const u32) -> bool {
|
||||
ptr.is_aligned()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: is_aligned_8
|
||||
// CHECK: testb $7, %dil
|
||||
// CHECK-NEXT: sete %al
|
||||
// CHECK-NEXT: retq
|
||||
#[no_mangle]
|
||||
pub fn is_aligned_8(ptr: *const u64) -> bool {
|
||||
ptr.is_aligned()
|
||||
}
|
Loading…
Reference in New Issue
Block a user