Skip to content

Commit daccb8c

Browse files
author
Lukas Markeffsky
committed
always use align_offset in is_aligned_to + add assembly test
1 parent 4696e89 commit daccb8c

File tree

3 files changed

+70
-26
lines changed

3 files changed

+70
-26
lines changed

library/core/src/ptr/const_ptr.rs

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,6 +1321,7 @@ impl<T: ?Sized> *const T {
13211321
/// # }
13221322
/// ```
13231323
#[must_use]
1324+
#[inline]
13241325
#[stable(feature = "align_offset", since = "1.36.0")]
13251326
#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")]
13261327
pub const fn align_offset(self, align: usize) -> usize
@@ -1562,19 +1563,11 @@ impl<T: ?Sized> *const T {
15621563
panic!("is_aligned_to: align is not a power-of-two")
15631564
}
15641565

1565-
#[inline]
1566-
fn runtime(ptr: *const u8, align: usize) -> bool {
1567-
ptr.addr() & (align - 1) == 0
1568-
}
1569-
1570-
// This optimizes to `(ptr + align - 1) & -align == ptr`, which is slightly
1571-
// slower than `ptr & (align - 1) == 0`
1572-
const fn comptime(ptr: *const u8, align: usize) -> bool {
1573-
ptr.align_offset(align) == 0
1574-
}
1575-
1576-
// SAFETY: `ptr.align_offset(align)` returns 0 if and only if the pointer is already aligned.
1577-
unsafe { intrinsics::const_eval_select((self.cast::<u8>(), align), comptime, runtime) }
1566+
// We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
1567+
// The cast to `()` is used to
1568+
// 1. deal with fat pointers; and
1569+
// 2. ensure that `align_offset` doesn't actually try to compute an offset.
1570+
self.cast::<()>().align_offset(align) == 0
15781571
}
15791572
}
15801573

library/core/src/ptr/mut_ptr.rs

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,6 +1589,7 @@ impl<T: ?Sized> *mut T {
15891589
/// # }
15901590
/// ```
15911591
#[must_use]
1592+
#[inline]
15921593
#[stable(feature = "align_offset", since = "1.36.0")]
15931594
#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")]
15941595
pub const fn align_offset(self, align: usize) -> usize
@@ -1830,19 +1831,11 @@ impl<T: ?Sized> *mut T {
18301831
panic!("is_aligned_to: align is not a power-of-two")
18311832
}
18321833

1833-
#[inline]
1834-
fn runtime(ptr: *mut u8, align: usize) -> bool {
1835-
ptr.addr() & (align - 1) == 0
1836-
}
1837-
1838-
// This optimizes to `(ptr + align - 1) & -align == ptr`, which is slightly
1839-
// slower than `ptr & (align - 1) == 0`
1840-
const fn comptime(ptr: *mut u8, align: usize) -> bool {
1841-
ptr.align_offset(align) == 0
1842-
}
1843-
1844-
// SAFETY: `ptr.align_offset(align)` returns 0 if and only if the pointer is already aligned.
1845-
unsafe { intrinsics::const_eval_select((self.cast::<u8>(), align), comptime, runtime) }
1834+
// We can't use the address of `self` in a `const fn`, so we use `align_offset` instead.
1835+
// The cast to `()` is used to
1836+
// 1. deal with fat pointers; and
1837+
// 2. ensure that `align_offset` doesn't actually try to compute an offset.
1838+
self.cast::<()>().align_offset(align) == 0
18461839
}
18471840
}
18481841

src/test/assembly/is_aligned.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// assembly-output: emit-asm
2+
// min-llvm-version: 14.0
3+
// only-x86_64
4+
// revisions: opt-speed opt-size
5+
// [opt-speed] compile-flags: -Copt-level=1
6+
// [opt-size] compile-flags: -Copt-level=s
7+
#![crate_type="rlib"]
8+
9+
#![feature(core_intrinsics)]
10+
#![feature(pointer_is_aligned)]
11+
12+
// CHECK-LABEL: is_aligned_to_unchecked
13+
// CHECK: decq %rsi
14+
// CHECK-NEXT: testq %rdi, %rsi
15+
// CHECK-NEXT: sete %al
16+
// CHECK-NEXT: retq
17+
#[no_mangle]
18+
pub unsafe fn is_aligned_to_unchecked(ptr: *const u8, align: usize) -> bool {
19+
unsafe {
20+
std::intrinsics::assume(align.is_power_of_two())
21+
}
22+
ptr.is_aligned_to(align)
23+
}
24+
25+
// CHECK-LABEL: is_aligned_1
26+
// CHECK: movb $1, %al
27+
// CHECK-NEXT: retq
28+
#[no_mangle]
29+
pub fn is_aligned_1(ptr: *const u8) -> bool {
30+
ptr.is_aligned()
31+
}
32+
33+
// CHECK-LABEL: is_aligned_2
34+
// CHECK: testb $1, %dil
35+
// CHECK-NEXT: sete %al
36+
// CHECK-NEXT: retq
37+
#[no_mangle]
38+
pub fn is_aligned_2(ptr: *const u16) -> bool {
39+
ptr.is_aligned()
40+
}
41+
42+
// CHECK-LABEL: is_aligned_4
43+
// CHECK: testb $3, %dil
44+
// CHECK-NEXT: sete %al
45+
// CHECK-NEXT: retq
46+
#[no_mangle]
47+
pub fn is_aligned_4(ptr: *const u32) -> bool {
48+
ptr.is_aligned()
49+
}
50+
51+
// CHECK-LABEL: is_aligned_8
52+
// CHECK: testb $7, %dil
53+
// CHECK-NEXT: sete %al
54+
// CHECK-NEXT: retq
55+
#[no_mangle]
56+
pub fn is_aligned_8(ptr: *const u64) -> bool {
57+
ptr.is_aligned()
58+
}

0 commit comments

Comments
 (0)