|
9 | 9 | use crate::cmp::Ordering::{self, Equal, Greater, Less};
|
10 | 10 | use crate::fmt;
|
11 | 11 | use crate::hint;
|
12 |
| -use crate::intrinsics::{exact_div, unchecked_sub}; |
| 12 | +use crate::intrinsics::{exact_div, select_unpredictable, unchecked_sub}; |
13 | 13 | use crate::mem::{self, SizedTypeProperties};
|
14 | 14 | use crate::num::NonZero;
|
15 | 15 | use crate::ops::{Bound, OneSidedRange, Range, RangeBounds};
|
@@ -2803,12 +2803,11 @@ impl<T> [T] {
|
2803 | 2803 | // we have `left + size/2 < self.len()`, and this is in-bounds.
|
2804 | 2804 | let cmp = f(unsafe { self.get_unchecked(mid) });
|
2805 | 2805 |
|
2806 |
| - // This control flow produces conditional moves, which results in |
2807 |
| - // fewer branches and instructions than if/else or matching on |
2808 |
| - // cmp::Ordering. |
2809 |
| - // This is x86 asm for u8: https://rust.godbolt.org/z/698eYffTx. |
2810 |
| - left = if cmp == Less { mid + 1 } else { left }; |
2811 |
| - right = if cmp == Greater { mid } else { right }; |
| 2806 | + // Binary search interacts poorly with branch prediction, so force |
| 2807 | + // the compiler to use conditional moves if supported by the target |
| 2808 | + // architecture. |
| 2809 | + left = select_unpredictable(cmp == Less, mid + 1, left); |
| 2810 | + right = select_unpredictable(cmp == Greater, mid, right); |
2812 | 2811 | if cmp == Equal {
|
2813 | 2812 | // SAFETY: same as the `get_unchecked` above
|
2814 | 2813 | unsafe { hint::assert_unchecked(mid < self.len()) };
|
|
0 commit comments