Rollup merge of #41143 - stjepang:optimize-bool-fetch-nand, r=nagisa

Optimize AtomicBool::fetch_nand

This is an attempt to push the PR #40563 to completion.

Benchmark: [source](https://gist.github.com/stjepang/023f5025623f5474184f9f4dfd6379ae)
Improvement:

```
 name  old_ ns/iter  new_ce_ ns/iter  diff ns/iter   diff %
 1t    146,440       89,904                -56,536  -38.61%
 2t    561,456       316,835              -244,621  -43.57%
 4t    2,822,821     1,005,424          -1,817,397  -64.38%
```

r? @eddyb
cc @alexcrichton @nagisa
This commit is contained in:
Tim Neumann 2017-04-08 08:55:09 +02:00 committed by GitHub
commit 2e4ab07fa0
2 changed files with 23 additions and 11 deletions

View file

@ -539,17 +539,16 @@ pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool {
// We can't use atomic_nand here because it can result in a bool with
// an invalid value. This happens because the atomic operation is done
// with an 8-bit integer internally, which would set the upper 7 bits.
// So we just use a compare-exchange loop instead, which is what the
// intrinsic actually expands to anyways on many platforms.
let mut old = self.load(Relaxed);
loop {
let new = !(old && val);
match self.compare_exchange_weak(old, new, order, Relaxed) {
Ok(_) => break,
Err(x) => old = x,
}
// So we just use fetch_xor or swap instead.
if val {
// !(x & true) == !x
// We must invert the bool.
self.fetch_xor(true, order)
} else {
// !(x & false) == true
// We must set the bool to true.
self.swap(true, order)
}
old
}
/// Logical "or" with a boolean value.

View file

@ -24,10 +24,23 @@ fn bool_() {
#[test]
fn bool_and() {
let a = AtomicBool::new(true);
assert_eq!(a.fetch_and(false, SeqCst),true);
assert_eq!(a.fetch_and(false, SeqCst), true);
assert_eq!(a.load(SeqCst),false);
}
#[test]
fn bool_nand() {
let a = AtomicBool::new(false);
assert_eq!(a.fetch_nand(false, SeqCst), false);
assert_eq!(a.load(SeqCst), true);
assert_eq!(a.fetch_nand(false, SeqCst), true);
assert_eq!(a.load(SeqCst), true);
assert_eq!(a.fetch_nand(true, SeqCst), true);
assert_eq!(a.load(SeqCst), false);
assert_eq!(a.fetch_nand(true, SeqCst), false);
assert_eq!(a.load(SeqCst), true);
}
#[test]
fn uint_and() {
let x = AtomicUsize::new(0xf731);