Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 14 additions & 17 deletions cmov/src/portable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@
// TODO(tarcieri): more optimized implementation for small integers

use crate::{Cmov, CmovEq, Condition};
use core::{hint::black_box, mem::size_of};
use core::hint::black_box;

/// Bitwise non-zero: returns `1` if `x != 0`, and otherwise returns `0`.
macro_rules! bitnz {
($value:expr, $bits:expr) => {
($value | $value.wrapping_neg()) >> ($bits - 1)
};
}

impl Cmov for u16 {
#[inline]
Expand Down Expand Up @@ -68,37 +75,27 @@ impl CmovEq for u32 {
impl Cmov for u64 {
#[inline]
fn cmovnz(&mut self, value: &Self, condition: Condition) {
let mask = is_non_zero(condition).wrapping_sub(1);
let mask = black_box((bitnz!(condition, u8::BITS) as u64).wrapping_sub(1));
*self = (*self & mask) | (*value & !mask);
}

#[inline]
fn cmovz(&mut self, value: &Self, condition: Condition) {
let mask = (1 ^ is_non_zero(condition)).wrapping_sub(1);
let mask = black_box((1 ^ bitnz!(condition, u8::BITS) as u64).wrapping_sub(1));
*self = (*self & mask) | (*value & !mask);
}
}

impl CmovEq for u64 {
#[inline]
fn cmovne(&self, rhs: &Self, input: Condition, output: &mut Condition) {
output.cmovnz(&input, (self ^ rhs) as u8);
let ne = bitnz!(self ^ rhs, u64::BITS) as u8;
output.cmovnz(&input, black_box(ne));
}

#[inline]
fn cmoveq(&self, rhs: &Self, input: Condition, output: &mut Condition) {
output.cmovz(&input, (self ^ rhs) as u8);
let ne = bitnz!(self ^ rhs, u64::BITS) as u8;
output.cmovnz(&input, black_box(ne ^ 1));
}
}

/// Check if the given condition value is non-zero
///
/// # Returns
/// - `condition` is zero: `0`
/// - `condition` is non-zero: `1`
#[inline]
fn is_non_zero(condition: Condition) -> u64 {
const SHIFT_BITS: usize = size_of::<u64>() - 1;
let condition = condition as u64;
black_box(((condition | (!condition).wrapping_add(1)) >> SHIFT_BITS) & 1)
}
3 changes: 0 additions & 3 deletions cmov/tests/proptests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
// TODO(tarcieri): known to be broken on PPC32. See RustCrypto/utils#1298
#![cfg(not(target_arch = "powerpc"))]

/// Write the proptests for an integer type.
macro_rules! int_proptests {
( $($int:ident),+ ) => {
Expand Down
3 changes: 0 additions & 3 deletions cmov/tests/regression.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
//! Tests for previous bugs in the implementation.

// TODO(tarcieri): known to be broken on PPC32. See RustCrypto/utils#1298
#![cfg(not(target_arch = "powerpc"))]

use cmov::CmovEq;

#[test]
Expand Down