diff options
| author | Lukas Markeffsky <@> | 2022-10-23 12:30:46 +0200 |
|---|---|---|
| committer | Lukas Markeffsky <@> | 2022-11-19 16:47:42 +0100 |
| commit | daccb8c11a464040acd744729231429dcb2e4d4b (patch) | |
| tree | 9aaa472de2ef31af30601afbd7918d5b8b8c6d6f | |
| parent | 4696e8906d362c1e10ffe40a5935de0ada45fb48 (diff) | |
| download | rust-daccb8c11a464040acd744729231429dcb2e4d4b.tar.gz rust-daccb8c11a464040acd744729231429dcb2e4d4b.zip | |
always use `align_offset` in `is_aligned_to` + add assembly test
| -rw-r--r-- | library/core/src/ptr/const_ptr.rs | 19 | ||||
| -rw-r--r-- | library/core/src/ptr/mut_ptr.rs | 19 | ||||
| -rw-r--r-- | src/test/assembly/is_aligned.rs | 58 |
3 files changed, 70 insertions, 26 deletions
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 @@ impl<T: ?Sized> *const 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 @@ impl<T: ?Sized> *const T { 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 } } 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 @@ impl<T: ?Sized> *mut 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 @@ impl<T: ?Sized> *mut T { 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 } } 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() +} |
