about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Markeffsky <@>2022-10-23 12:30:46 +0200
committerLukas Markeffsky <@>2022-11-19 16:47:42 +0100
commitdaccb8c11a464040acd744729231429dcb2e4d4b (patch)
tree9aaa472de2ef31af30601afbd7918d5b8b8c6d6f
parent4696e8906d362c1e10ffe40a5935de0ada45fb48 (diff)
downloadrust-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.rs19
-rw-r--r--library/core/src/ptr/mut_ptr.rs19
-rw-r--r--src/test/assembly/is_aligned.rs58
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()
+}