From daccb8c11a464040acd744729231429dcb2e4d4b Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Sun, 23 Oct 2022 12:30:46 +0200 Subject: [PATCH] always use `align_offset` in `is_aligned_to` + add assembly test --- library/core/src/ptr/const_ptr.rs | 19 ++++------ library/core/src/ptr/mut_ptr.rs | 19 ++++------ src/test/assembly/is_aligned.rs | 58 +++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 26 deletions(-) create mode 100644 src/test/assembly/is_aligned.rs diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index d042f22f026..82a01a70a41 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -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::(), 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 } } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 764fa9d8ba8..fdb99818ac7 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -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::(), 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 } } diff --git a/src/test/assembly/is_aligned.rs b/src/test/assembly/is_aligned.rs new file mode 100644 index 00000000000..3949f5f6530 --- /dev/null +++ b/src/test/assembly/is_aligned.rs @@ -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() +}