diff options
| author | Scott McMurray <scottmcm@users.noreply.github.com> | 2023-08-02 12:45:52 -0700 |
|---|---|---|
| committer | Scott McMurray <scottmcm@users.noreply.github.com> | 2023-08-06 15:47:40 -0700 |
| commit | 502af03445f045dade14f14e754803f02c2c5e24 (patch) | |
| tree | fbeb208e1c6d7df46431f1412404e8b48dfd5349 /library/core/src | |
| parent | 85fbb571497d13cfb828de9b0d3e78656b9203c1 (diff) | |
| download | rust-502af03445f045dade14f14e754803f02c2c5e24.tar.gz rust-502af03445f045dade14f14e754803f02c2c5e24.zip | |
Add a new `compare_bytes` intrinsic instead of calling `memcmp` directly
Diffstat (limited to 'library/core/src')
| -rw-r--r-- | library/core/src/intrinsics.rs | 34 | ||||
| -rw-r--r-- | library/core/src/slice/cmp.rs | 21 |
2 files changed, 40 insertions, 15 deletions
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index d042aaf3084..9ef2c7cde02 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2385,6 +2385,25 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn raw_eq<T>(a: &T, b: &T) -> bool; + /// Lexicographically compare `[left, left + bytes)` and `[right, right + bytes)` + /// as unsigned bytes, returning negative if `left` is less, zero if all the + /// bytes match, or positive if `right` is greater. + /// + /// This underlies things like `<[u8]>::cmp`, and will usually lower to `memcmp`. + /// + /// # Safety + /// + /// `left` and `right` must each be [valid] for reads of `bytes` bytes. + /// + /// Note that this applies to the whole range, not just until the first byte + /// that differs. That allows optimizations that can read in large chunks. + /// + /// [valid]: crate::ptr#safety + #[cfg(not(bootstrap))] + #[rustc_const_unstable(feature = "const_intrinsic_compare_bytes", issue = "none")] + #[rustc_nounwind] + pub fn compare_bytes(left: *const u8, right: *const u8, bytes: usize) -> i32; + /// See documentation of [`std::hint::black_box`] for details. /// /// [`std::hint::black_box`]: crate::hint::black_box @@ -2825,3 +2844,18 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) { write_bytes(dst, val, count) } } + +/// Backfill for bootstrap +#[cfg(bootstrap)] +pub unsafe fn compare_bytes(left: *const u8, right: *const u8, bytes: usize) -> i32 { + extern "C" { + fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> crate::ffi::c_int; + } + + if bytes != 0 { + // SAFETY: Since bytes is non-zero, the caller has met `memcmp`'s requirements. + unsafe { memcmp(left, right, bytes).into() } + } else { + 0 + } +} diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index 7601dd3c756..075347b80d0 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -1,22 +1,12 @@ //! Comparison traits for `[T]`. use crate::cmp::{self, BytewiseEq, Ordering}; -use crate::ffi; +use crate::intrinsics::compare_bytes; use crate::mem; use super::from_raw_parts; use super::memchr; -extern "C" { - /// Calls implementation provided memcmp. - /// - /// Interprets the data as u8. - /// - /// Returns 0 for equal, < 0 for less than and > 0 for greater - /// than. - fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> ffi::c_int; -} - #[stable(feature = "rust1", since = "1.0.0")] impl<A, B> PartialEq<[B]> for [A] where @@ -74,7 +64,8 @@ where } } -// Use memcmp for bytewise equality when the types allow +// When each element can be compared byte-wise, we can compare all the bytes +// from the whole size in one call to the intrinsics. impl<A, B> SlicePartialEq<B> for [A] where A: BytewiseEq<B>, @@ -88,7 +79,7 @@ where // The two slices have been checked to have the same size above. unsafe { let size = mem::size_of_val(self); - memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0 + compare_bytes(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0 } } } @@ -183,7 +174,7 @@ impl<A: Ord> SliceOrd for A { } } -// memcmp compares a sequence of unsigned bytes lexicographically. +// `compare_bytes` compares a sequence of unsigned bytes lexicographically. // this matches the order we want for [u8], but no others (not even [i8]). impl SliceOrd for u8 { #[inline] @@ -195,7 +186,7 @@ impl SliceOrd for u8 { // SAFETY: `left` and `right` are references and are thus guaranteed to be valid. // We use the minimum of both lengths which guarantees that both regions are // valid for reads in that interval. - let mut order = unsafe { memcmp(left.as_ptr(), right.as_ptr(), len) as isize }; + let mut order = unsafe { compare_bytes(left.as_ptr(), right.as_ptr(), len) as isize }; if order == 0 { order = diff; } |
