diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 5070d678c9fab..f28b0c1b001d4 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2753,6 +2753,9 @@ pub fn declare_intrinsics(llmod: ModuleRef) -> HashMap<&'static str, ValueRef> { ifn!("llvm.bswap.i32",[Type::i32()], Type::i32()); ifn!("llvm.bswap.i64",[Type::i64()], Type::i64()); + ifn!("llvm.expect.i32",[Type::i32(), Type::i32()], Type::i32()); + ifn!("llvm.expect.i64",[Type::i64(), Type::i64()], Type::i64()); + return intrinsics; } diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 20c8e69129d74..4ac315b32bb4c 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -939,6 +939,8 @@ pub fn trans_intrinsic(ccx: @mut CrateContext, "bswap16" => simple_llvm_intrinsic(bcx, "llvm.bswap.i16", 1), "bswap32" => simple_llvm_intrinsic(bcx, "llvm.bswap.i32", 1), "bswap64" => simple_llvm_intrinsic(bcx, "llvm.bswap.i64", 1), + "expect32" => simple_llvm_intrinsic(bcx, "llvm.expect.i32", 2), + "expect64" => simple_llvm_intrinsic(bcx, "llvm.expect.i64", 2), _ => { // Could we make this an enum rather than a string? does it get // checked earlier? diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs index 42d5527ee43bc..0296e7675d9c2 100644 --- a/src/librustc/middle/trans/type_use.rs +++ b/src/librustc/middle/trans/type_use.rs @@ -167,6 +167,8 @@ pub fn type_uses_for(ccx: @mut CrateContext, fn_id: def_id, n_tps: uint) "bswap16" | "bswap32" | "bswap64" => 0, + "expect32" | "expect64" => 0, + // would be cool to make these an enum instead of // strings! _ => fail!("unknown intrinsic in type_use") diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 7f486f77447cb..f5fe5caed4df3 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -3634,6 +3634,8 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { "bswap16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()), "bswap32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()), "bswap64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()), + "expect32" => (0, ~[ ty::mk_u32(), ty::mk_u32() ], ty::mk_u32()), + "expect64" => (0, ~[ ty::mk_u64(), ty::mk_u64() ], ty::mk_u64()), ref other => { tcx.sess.span_err(it.span, fmt!("unrecognized intrinsic function: `%s`", diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 04058887970d0..64114f1d4c007 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -35,7 +35,7 @@ macro_rules! rtdebug ( macro_rules! rtassert ( ( $arg:expr ) => ( { - if !$arg { + if ::std::unstable::intrinsics::unlikely(!$arg) { rtabort!("assertion failed: %s", stringify!($arg)); } } ) diff --git a/src/libstd/unstable/intrinsics.rs b/src/libstd/unstable/intrinsics.rs index 1270a80c35499..2f8f5efa42c22 100644 --- a/src/libstd/unstable/intrinsics.rs +++ b/src/libstd/unstable/intrinsics.rs @@ -419,6 +419,11 @@ extern "rust-intrinsic" { pub fn bswap16(x: i16) -> i16; pub fn bswap32(x: i32) -> i32; pub fn bswap64(x: i64) -> i64; + + #[cfg(not(stage0))] + pub fn expect32(value: u32, expected: u32) -> u32; + #[cfg(not(stage0))] + pub fn expect64(value: u64, expected: u64) -> u64; } #[cfg(target_endian = "little")] pub fn to_le16(x: i16) -> i16 { x } @@ -434,3 +439,44 @@ extern "rust-intrinsic" { #[cfg(target_endian = "big")] pub fn to_be32(x: i32) -> i32 { x } #[cfg(target_endian = "little")] pub fn to_be64(x: i64) -> i64 { unsafe { bswap64(x) } } #[cfg(target_endian = "big")] pub fn to_be64(x: i64) -> i64 { x } + +#[cfg(not(stage0))] +#[inline(always)] +pub fn likely(cond: bool) -> bool { + unsafe { + expect32(cond as u32, 1) as bool + } +} + +#[cfg(not(stage0))] +#[inline(always)] +pub fn unlikely(cond: bool) -> bool { + unsafe { + expect32(cond as u32, 0) as bool + } +} + +#[cfg(stage0)] +#[inline(always)] +pub fn likely(cond: bool) -> bool { + cond +} + +#[cfg(stage0)] +#[inline(always)] +pub fn unlikely(cond: bool) -> bool { + cond +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_likely_unlikely() { + assert_eq!(true, likely(true)); + assert_eq!(false, likely(false)); + assert_eq!(true, unlikely(true)); + assert_eq!(false, unlikely(false)); + } +} diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index a6c5526b5a9b4..7f8836fa5a667 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -799,18 +799,18 @@ pub fn std_macros() -> @str { macro_rules! assert( ($cond:expr) => { - if !$cond { + if ::std::unstable::intrinsics::unlikely(!$cond) { ::std::sys::FailWithCause::fail_with( \"assertion failed: \" + stringify!($cond), file!(), line!()) } }; ($cond:expr, $msg:expr) => { - if !$cond { + if ::std::unstable::intrinsics::unlikely(!$cond) { ::std::sys::FailWithCause::fail_with($msg, file!(), line!()) } }; ($cond:expr, $( $arg:expr ),+) => { - if !$cond { + if ::std::unstable::intrinsics::unlikely(!$cond) { ::std::sys::FailWithCause::fail_with(fmt!( $($arg),+ ), file!(), line!()) } } @@ -822,7 +822,9 @@ pub fn std_macros() -> @str { let given_val = $given; let expected_val = $expected; // check both directions of equality.... - if !((given_val == expected_val) && (expected_val == given_val)) { + if ::std::unstable::intrinsics::unlikely( + !((given_val == expected_val) && (expected_val == given_val))) + { fail!(\"assertion failed: `(left == right) && (right == \ left)` (left: `%?`, right: `%?`)\", given_val, expected_val); } @@ -838,10 +840,10 @@ pub fn std_macros() -> @str { let given_val = $given; let expected_val = $expected; // check both directions of equality.... - if !( + if ::std::unstable::intrinsics::unlikely(!( given_val.approx_eq(&expected_val) && expected_val.approx_eq(&given_val) - ) { + )) { fail!(\"left: %? does not approximately equal right: %?\", given_val, expected_val); } @@ -855,10 +857,10 @@ pub fn std_macros() -> @str { let expected_val = $expected; let epsilon_val = $epsilon; // check both directions of equality.... - if !( + if ::std::unstable::intrinsics::unlikely(!( given_val.approx_eq_eps(&expected_val, &epsilon_val) && expected_val.approx_eq_eps(&given_val, &epsilon_val) - ) { + )) { fail!(\"left: %? does not approximately equal right: %? with epsilon: %?\", given_val, expected_val, epsilon_val); }