]> git.lizzy.rs Git - rust.git/commitdiff
Make [u8]::cmp implementation branchless
authorjoboet <jonasboettiger@icloud.com>
Sun, 13 Feb 2022 12:19:18 +0000 (13:19 +0100)
committerjoboet <jonasboettiger@icloud.com>
Mon, 14 Feb 2022 22:16:35 +0000 (23:16 +0100)
library/core/src/slice/cmp.rs

index 72af47c71dd64333b9c4d4e12c9104540678736b..27c6b6f5bc02f474a8954a54c53de4f7f6347ed9 100644 (file)
@@ -1,7 +1,6 @@
 //! Comparison traits for `[T]`.
 
-use crate::cmp;
-use crate::cmp::Ordering::{self, Greater, Less};
+use crate::cmp::{self, Ordering};
 use crate::mem;
 
 use super::from_raw_parts;
@@ -189,18 +188,18 @@ impl<A: Ord> SliceOrd for A {
 impl SliceOrd for u8 {
     #[inline]
     fn compare(left: &[Self], right: &[Self]) -> Ordering {
-        let order =
-            // 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.
-            unsafe { memcmp(left.as_ptr(), right.as_ptr(), cmp::min(left.len(), right.len())) };
+        // Since the length of a slice is always less than or equal to isize::MAX, this never underflows.
+        let diff = left.len() as isize - right.len() as isize;
+        // This comparison gets optimized away (on x86_64 and ARM) because the subtraction updates flags.
+        let len = if left.len() < right.len() { left.len() } else { right.len() };
+        // 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 };
         if order == 0 {
-            left.len().cmp(&right.len())
-        } else if order < 0 {
-            Less
-        } else {
-            Greater
+            order = diff;
         }
+        order.cmp(&0)
     }
 }