Skip to content

Commit 4682a24

Browse files
authored
Rollup merge of rust-lang#133695 - x17jiri:hint_likely, r=Amanieu
Reexport likely/unlikely in std::hint Since `likely`/`unlikely` should be working now, we could reexport them in `std::hint`. I'm not sure if this is already approved or if it requires approval Tracking issue: rust-lang#26179
2 parents 9f4d9dc + cb2efaf commit 4682a24

File tree

6 files changed

+354
-4
lines changed

6 files changed

+354
-4
lines changed

library/core/src/hint.rs

+135
Original file line numberDiff line numberDiff line change
@@ -597,3 +597,138 @@ pub const fn black_box<T>(dummy: T) -> T {
597597
pub const fn must_use<T>(value: T) -> T {
598598
value
599599
}
600+
601+
/// Hints to the compiler that a branch condition is likely to be true.
602+
/// Returns the value passed to it.
603+
///
604+
/// It can be used with `if` or boolean `match` expressions.
605+
///
606+
/// When used outside of a branch condition, it may still influence a nearby branch, but
607+
/// probably will not have any effect.
608+
///
609+
/// It can also be applied to parts of expressions, such as `likely(a) && unlikely(b)`, or to
610+
/// compound expressions, such as `likely(a && b)`. When applied to compound expressions, it has
611+
/// the following effect:
612+
/// ```text
613+
/// likely(!a) => !unlikely(a)
614+
/// likely(a && b) => likely(a) && likely(b)
615+
/// likely(a || b) => a || likely(b)
616+
/// ```
617+
///
618+
/// See also the function [`cold_path()`] which may be more appropriate for idiomatic Rust code.
619+
///
620+
/// # Examples
621+
///
622+
/// ```
623+
/// #![feature(likely_unlikely)]
624+
/// use core::hint::likely;
625+
///
626+
/// fn foo(x: i32) {
627+
/// if likely(x > 0) {
628+
/// println!("this branch is likely to be taken");
629+
/// } else {
630+
/// println!("this branch is unlikely to be taken");
631+
/// }
632+
///
633+
/// match likely(x > 0) {
634+
/// true => println!("this branch is likely to be taken"),
635+
/// false => println!("this branch is unlikely to be taken"),
636+
/// }
637+
///
638+
/// // Use outside of a branch condition may still influence a nearby branch
639+
/// let cond = likely(x != 0);
640+
/// if cond {
641+
/// println!("this branch is likely to be taken");
642+
/// }
643+
/// }
644+
/// ```
645+
///
646+
///
647+
#[unstable(feature = "likely_unlikely", issue = "26179")]
648+
#[inline(always)]
649+
pub const fn likely(b: bool) -> bool {
650+
crate::intrinsics::likely(b)
651+
}
652+
653+
/// Hints to the compiler that a branch condition is unlikely to be true.
654+
/// Returns the value passed to it.
655+
///
656+
/// It can be used with `if` or boolean `match` expressions.
657+
///
658+
/// When used outside of a branch condition, it may still influence a nearby branch, but
659+
/// probably will not have any effect.
660+
///
661+
/// It can also be applied to parts of expressions, such as `likely(a) && unlikely(b)`, or to
662+
/// compound expressions, such as `unlikely(a && b)`. When applied to compound expressions, it has
663+
/// the following effect:
664+
/// ```text
665+
/// unlikely(!a) => !likely(a)
666+
/// unlikely(a && b) => a && unlikely(b)
667+
/// unlikely(a || b) => unlikely(a) || unlikely(b)
668+
/// ```
669+
///
670+
/// See also the function [`cold_path()`] which may be more appropriate for idiomatic Rust code.
671+
///
672+
/// # Examples
673+
///
674+
/// ```
675+
/// #![feature(likely_unlikely)]
676+
/// use core::hint::unlikely;
677+
///
678+
/// fn foo(x: i32) {
679+
/// if unlikely(x > 0) {
680+
/// println!("this branch is unlikely to be taken");
681+
/// } else {
682+
/// println!("this branch is likely to be taken");
683+
/// }
684+
///
685+
/// match unlikely(x > 0) {
686+
/// true => println!("this branch is unlikely to be taken"),
687+
/// false => println!("this branch is likely to be taken"),
688+
/// }
689+
///
690+
/// // Use outside of a branch condition may still influence a nearby branch
691+
/// let cond = unlikely(x != 0);
692+
/// if cond {
693+
/// println!("this branch is likely to be taken");
694+
/// }
695+
/// }
696+
/// ```
697+
#[unstable(feature = "likely_unlikely", issue = "26179")]
698+
#[inline(always)]
699+
pub const fn unlikely(b: bool) -> bool {
700+
crate::intrinsics::unlikely(b)
701+
}
702+
703+
/// Hints to the compiler that given path is cold, i.e., unlikely to be taken. The compiler may
704+
/// choose to optimize paths that are not cold at the expense of paths that are cold.
705+
///
706+
/// # Examples
707+
///
708+
/// ```
709+
/// #![feature(cold_path)]
710+
/// use core::hint::cold_path;
711+
///
712+
/// fn foo(x: &[i32]) {
713+
/// if let Some(first) = x.get(0) {
714+
/// // this is the fast path
715+
/// } else {
716+
/// // this path is unlikely
717+
/// cold_path();
718+
/// }
719+
/// }
720+
///
721+
/// fn bar(x: i32) -> i32 {
722+
/// match x {
723+
/// 1 => 10,
724+
/// 2 => 100,
725+
/// 3 => { cold_path(); 1000 }, // this branch is unlikely
726+
/// _ => { cold_path(); 10000 }, // this is also unlikely
727+
/// }
728+
/// }
729+
/// ```
730+
#[unstable(feature = "cold_path", issue = "26179")]
731+
#[inline(always)]
732+
pub const fn cold_path() {
733+
crate::intrinsics::cold_path()
734+
}

tests/codegen/hint/cold_path.rs

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//@ compile-flags: -O
2+
#![crate_type = "lib"]
3+
#![feature(cold_path)]
4+
5+
use std::hint::cold_path;
6+
7+
#[inline(never)]
8+
#[no_mangle]
9+
pub fn path_a() {
10+
println!("path a");
11+
}
12+
13+
#[inline(never)]
14+
#[no_mangle]
15+
pub fn path_b() {
16+
println!("path b");
17+
}
18+
19+
#[no_mangle]
20+
pub fn test1(x: bool) {
21+
if x {
22+
path_a();
23+
} else {
24+
cold_path();
25+
path_b();
26+
}
27+
28+
// CHECK-LABEL: @test1(
29+
// CHECK: br i1 %x, label %bb1, label %bb2, !prof ![[NUM:[0-9]+]]
30+
// CHECK: bb2:
31+
// CHECK: path_b
32+
// CHECK: bb1:
33+
// CHECK: path_a
34+
}
35+
36+
#[no_mangle]
37+
pub fn test2(x: i32) {
38+
match x > 0 {
39+
true => path_a(),
40+
false => {
41+
cold_path();
42+
path_b()
43+
}
44+
}
45+
46+
// CHECK-LABEL: @test2(
47+
// CHECK: br i1 %_2, label %bb2, label %bb1, !prof ![[NUM]]
48+
// CHECK: bb1:
49+
// CHECK: path_b
50+
// CHECK: bb2:
51+
// CHECK: path_a
52+
}
53+
54+
// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1}

tests/codegen/hint/likely.rs

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//@ compile-flags: -O
2+
#![crate_type = "lib"]
3+
#![feature(likely_unlikely)]
4+
5+
use std::hint::likely;
6+
7+
#[inline(never)]
8+
#[no_mangle]
9+
pub fn path_a() {
10+
println!("path a");
11+
}
12+
13+
#[inline(never)]
14+
#[no_mangle]
15+
pub fn path_b() {
16+
println!("path b");
17+
}
18+
19+
#[no_mangle]
20+
pub fn test1(x: bool) {
21+
if likely(x) {
22+
path_a();
23+
} else {
24+
path_b();
25+
}
26+
27+
// CHECK-LABEL: @test1(
28+
// CHECK: br i1 %x, label %bb2, label %bb3, !prof ![[NUM:[0-9]+]]
29+
// CHECK: bb3:
30+
// CHECK: path_b
31+
// CHECK: bb2:
32+
// CHECK: path_a
33+
}
34+
35+
#[no_mangle]
36+
pub fn test2(x: i32) {
37+
match likely(x > 0) {
38+
true => path_a(),
39+
false => path_b(),
40+
}
41+
42+
// CHECK-LABEL: @test2(
43+
// CHECK: br i1 %_2, label %bb2, label %bb3, !prof ![[NUM]]
44+
// CHECK: bb3:
45+
// CHECK: path_b
46+
// CHECK: bb2:
47+
// CHECK: path_a
48+
}
49+
50+
#[no_mangle]
51+
pub fn test3(x: i8) {
52+
match likely(x < 7) {
53+
true => path_a(),
54+
_ => path_b(),
55+
}
56+
57+
// CHECK-LABEL: @test3(
58+
// CHECK: br i1 %_2, label %bb2, label %bb3, !prof ![[NUM]]
59+
// CHECK: bb3:
60+
// CHECK: path_b
61+
// CHECK: bb2:
62+
// CHECK: path_a
63+
}
64+
65+
#[no_mangle]
66+
pub fn test4(x: u64) {
67+
match likely(x != 33) {
68+
false => path_a(),
69+
_ => path_b(),
70+
}
71+
72+
// CHECK-LABEL: @test4(
73+
// CHECK: br i1 %0, label %bb3, label %bb2, !prof ![[NUM2:[0-9]+]]
74+
// CHECK: bb3:
75+
// CHECK: path_a
76+
// CHECK: bb2:
77+
// CHECK: path_b
78+
}
79+
80+
// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1}
81+
// CHECK: ![[NUM2]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000}

tests/codegen/hint/unlikely.rs

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//@ compile-flags: -O
2+
#![crate_type = "lib"]
3+
#![feature(likely_unlikely)]
4+
5+
use std::hint::unlikely;
6+
7+
#[inline(never)]
8+
#[no_mangle]
9+
pub fn path_a() {
10+
println!("path a");
11+
}
12+
13+
#[inline(never)]
14+
#[no_mangle]
15+
pub fn path_b() {
16+
println!("path b");
17+
}
18+
19+
#[no_mangle]
20+
pub fn test1(x: bool) {
21+
if unlikely(x) {
22+
path_a();
23+
} else {
24+
path_b();
25+
}
26+
27+
// CHECK-LABEL: @test1(
28+
// CHECK: br i1 %x, label %bb2, label %bb4, !prof ![[NUM:[0-9]+]]
29+
// CHECK: bb4:
30+
// CHECK: path_b
31+
// CHECK: bb2:
32+
// CHECK: path_a
33+
}
34+
35+
#[no_mangle]
36+
pub fn test2(x: i32) {
37+
match unlikely(x > 0) {
38+
true => path_a(),
39+
false => path_b(),
40+
}
41+
42+
// CHECK-LABEL: @test2(
43+
// CHECK: br i1 %_2, label %bb2, label %bb4, !prof ![[NUM]]
44+
// CHECK: bb4:
45+
// CHECK: path_b
46+
// CHECK: bb2:
47+
// CHECK: path_a
48+
}
49+
50+
#[no_mangle]
51+
pub fn test3(x: i8) {
52+
match unlikely(x < 7) {
53+
true => path_a(),
54+
_ => path_b(),
55+
}
56+
57+
// CHECK-LABEL: @test3(
58+
// CHECK: br i1 %_2, label %bb2, label %bb4, !prof ![[NUM]]
59+
// CHECK: bb4:
60+
// CHECK: path_b
61+
// CHECK: bb2:
62+
// CHECK: path_a
63+
}
64+
65+
#[no_mangle]
66+
pub fn test4(x: u64) {
67+
match unlikely(x != 33) {
68+
false => path_a(),
69+
_ => path_b(),
70+
}
71+
72+
// CHECK-LABEL: @test4(
73+
// CHECK: br i1 %0, label %bb4, label %bb2, !prof ![[NUM2:[0-9]+]]
74+
// CHECK: bb4:
75+
// CHECK: path_a
76+
// CHECK: bb2:
77+
// CHECK: path_b
78+
}
79+
80+
// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000}

tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ fn step_forward(_1: u16, _2: usize) -> u16 {
1313
scope 6 (inlined core::num::<impl u16>::checked_add) {
1414
let mut _5: (u16, bool);
1515
let mut _6: bool;
16-
scope 7 (inlined unlikely) {
16+
scope 7 (inlined std::intrinsics::unlikely) {
1717
let _7: ();
1818
}
1919
}
@@ -55,7 +55,7 @@ fn step_forward(_1: u16, _2: usize) -> u16 {
5555
}
5656

5757
bb3: {
58-
_7 = cold_path() -> [return: bb4, unwind unreachable];
58+
_7 = std::intrinsics::cold_path() -> [return: bb4, unwind unreachable];
5959
}
6060

6161
bb4: {

tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ fn step_forward(_1: u16, _2: usize) -> u16 {
1313
scope 6 (inlined core::num::<impl u16>::checked_add) {
1414
let mut _5: (u16, bool);
1515
let mut _6: bool;
16-
scope 7 (inlined unlikely) {
16+
scope 7 (inlined std::intrinsics::unlikely) {
1717
let _7: ();
1818
}
1919
}
@@ -55,7 +55,7 @@ fn step_forward(_1: u16, _2: usize) -> u16 {
5555
}
5656

5757
bb3: {
58-
_7 = cold_path() -> [return: bb4, unwind unreachable];
58+
_7 = std::intrinsics::cold_path() -> [return: bb4, unwind unreachable];
5959
}
6060

6161
bb4: {

0 commit comments

Comments
 (0)