Skip to content

Commit 2fd0608

Browse files
authored
Auto merge of #36181 - seanmonstar:likely, r=nikomatsakis
core: add likely and unlikely intrinsics I'm no good at reading assembly, but I have tried a stage1 compiler with this patch, and it does cause different asm output. Additionally, testing this compiler on my httparse crate with some `likely` usage added in to the branches does affect benchmarks. However, I'm sure a codegen test should be included, if anyone knows what it should look like. There isn't an entry in `librustc_trans/context.rs` in this diff, because it already exists (`llvm.expect.i1` is used for array indices). ---- Even though this does affect httparse benchmarks, it doesn't seem to affect it the same way GCC's `__builtin_expect` affects picohttpparser. I was confused that the deviation on the benchmarks grew hugely when testing this, especially since I'm absolutely certain that the branchs where I added `likely` were always `true`. I chalk that up to GCC and LLVM handle branch prediction differently. cc #26179
2 parents c87ba3f + b778f7f commit 2fd0608

File tree

4 files changed

+65
-0
lines changed

4 files changed

+65
-0
lines changed

src/libcore/intrinsics.rs

+14
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,20 @@ extern "rust-intrinsic" {
194194
/// own, or if it does not enable any significant optimizations.
195195
pub fn assume(b: bool);
196196

197+
#[cfg(not(stage0))]
198+
/// Hints to the compiler that branch condition is likely to be true.
199+
/// Returns the value passed to it.
200+
///
201+
/// Any use other than with `if` statements will probably not have an effect.
202+
pub fn likely(b: bool) -> bool;
203+
204+
#[cfg(not(stage0))]
205+
/// Hints to the compiler that branch condition is likely to be false.
206+
/// Returns the value passed to it.
207+
///
208+
/// Any use other than with `if` statements will probably not have an effect.
209+
pub fn unlikely(b: bool) -> bool;
210+
197211
/// Executes a breakpoint trap, for inspection by a debugger.
198212
pub fn breakpoint();
199213

src/librustc_trans/intrinsic.rs

+8
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,14 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
136136
(Some(llfn), _) => {
137137
Call(bcx, llfn, &llargs, call_debug_location)
138138
}
139+
(_, "likely") => {
140+
let expect = ccx.get_intrinsic(&("llvm.expect.i1"));
141+
Call(bcx, expect, &[llargs[0], C_bool(ccx, true)], call_debug_location)
142+
}
143+
(_, "unlikely") => {
144+
let expect = ccx.get_intrinsic(&("llvm.expect.i1"));
145+
Call(bcx, expect, &[llargs[0], C_bool(ccx, false)], call_debug_location)
146+
}
139147
(_, "try") => {
140148
bcx = try_intrinsic(bcx, llargs[0], llargs[1], llargs[2], llresult,
141149
call_debug_location);

src/librustc_typeck/check/intrinsic.rs

+2
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,8 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
285285
(1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)),
286286

287287
"assume" => (0, vec![tcx.types.bool], tcx.mk_nil()),
288+
"likely" => (0, vec![tcx.types.bool], tcx.types.bool),
289+
"unlikely" => (0, vec![tcx.types.bool], tcx.types.bool),
288290

289291
"discriminant_value" => (1, vec![
290292
tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1),

src/test/codegen/likely.rs

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// compile-flags: -C no-prepopulate-passes
12+
13+
#![crate_type = "lib"]
14+
#![feature(core_intrinsics)]
15+
16+
use std::intrinsics::{likely,unlikely};
17+
18+
#[no_mangle]
19+
pub fn check_likely(x: i32, y: i32) -> Option<i32> {
20+
unsafe {
21+
// CHECK: call i1 @llvm.expect.i1(i1 %{{.*}}, i1 true)
22+
if likely(x == y) {
23+
None
24+
} else {
25+
Some(x + y)
26+
}
27+
}
28+
}
29+
30+
#[no_mangle]
31+
pub fn check_unlikely(x: i32, y: i32) -> Option<i32> {
32+
unsafe {
33+
// CHECK: call i1 @llvm.expect.i1(i1 %{{.*}}, i1 false)
34+
if unlikely(x == y) {
35+
None
36+
} else {
37+
Some(x + y)
38+
}
39+
}
40+
}
41+

0 commit comments

Comments
 (0)