Skip to content

Commit

Permalink
Merge pull request #366 from DaniPopes/perfington1
Browse files Browse the repository at this point in the history
perf: use borrowing/carrying ops in add/sub, remove bound checks in shifts
  • Loading branch information
prestwich authored Apr 20, 2024
2 parents 41c45f8 + 69d53ed commit 46fc569
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 28 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- Use borrowing/carrying ops in add/sub, remove bound checks in shifts ([#366])

### Fixed

- add `alloc` requirement to `num-traits` feature [#363]
- Add `alloc` requirement to `num-traits` feature [#363]

[#363]: https://github.com/recmo/uint/pull/363
[#366]: https://github.com/recmo/uint/pull/366

## [1.12.1] - 2024-03-12

Expand Down
35 changes: 22 additions & 13 deletions src/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,24 @@ impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
#[inline]
#[must_use]
pub const fn overflowing_add(mut self, rhs: Self) -> (Self, bool) {
// TODO: Replace with `u64::carrying_add` once stable.
#[inline]
const fn u64_carrying_add(lhs: u64, rhs: u64, carry: bool) -> (u64, bool) {
let (a, b) = lhs.overflowing_add(rhs);
let (c, d) = a.overflowing_add(carry as u64);
(c, b || d)
}

if BITS == 0 {
return (Self::ZERO, false);
}
let mut carry = 0_u128;
let mut carry = false;
let mut i = 0;
#[allow(clippy::cast_possible_truncation)] // Intentional
while i < LIMBS {
carry += self.limbs[i] as u128 + rhs.limbs[i] as u128;
self.limbs[i] = carry as u64;
carry >>= 64;
(self.limbs[i], carry) = u64_carrying_add(self.limbs[i], rhs.limbs[i], carry);
i += 1;
}
let overflow = carry != 0 || self.limbs[LIMBS - 1] > Self::MASK;
let overflow = carry || self.limbs[LIMBS - 1] > Self::MASK;
self.limbs[LIMBS - 1] &= Self::MASK;
(self, overflow)
}
Expand All @@ -93,20 +98,24 @@ impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
#[inline]
#[must_use]
pub const fn overflowing_sub(mut self, rhs: Self) -> (Self, bool) {
// TODO: Replace with `u64::borrowing_sub` once stable.
#[inline]
const fn u64_borrowing_sub(lhs: u64, rhs: u64, borrow: bool) -> (u64, bool) {
let (a, b) = lhs.overflowing_sub(rhs);
let (c, d) = a.overflowing_sub(borrow as u64);
(c, b || d)
}

if BITS == 0 {
return (Self::ZERO, false);
}
let mut carry = 0_i128;
let mut borrow = false;
let mut i = 0;
#[allow(clippy::cast_possible_truncation)] // Intentional
#[allow(clippy::cast_sign_loss)] // Intentional
while i < LIMBS {
carry += self.limbs[i] as i128 - rhs.limbs[i] as i128;
self.limbs[i] = carry as u64;
carry >>= 64;
(self.limbs[i], borrow) = u64_borrowing_sub(self.limbs[i], rhs.limbs[i], borrow);
i += 1;
}
let overflow = carry != 0 || self.limbs[LIMBS - 1] > Self::MASK;
let overflow = borrow || self.limbs[LIMBS - 1] > Self::MASK;
self.limbs[LIMBS - 1] &= Self::MASK;
(self, overflow)
}
Expand Down
1 change: 0 additions & 1 deletion src/algorithms/div/knuth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use crate::{
algorithms::{add::adc_n, mul::submul_nx1},
utils::{likely, unlikely},
};
use core::u64;

/// ⚠️ In-place Knuth normalized long division with reciprocals.
///
Expand Down
23 changes: 10 additions & 13 deletions src/bits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,11 +271,10 @@ impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {

// Shift
for i in (limbs..LIMBS).rev() {
assume!(i >= limbs && i - limbs < LIMBS);
self.limbs[i] = self.limbs[i - limbs];
}
for i in 0..limbs {
self.limbs[i] = 0;
}
self.limbs[..limbs].fill(0);
self.limbs[LIMBS - 1] &= Self::MASK;
return (self, overflow);
}
Expand All @@ -294,13 +293,12 @@ impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {

// Shift
for i in (limbs + 1..LIMBS).rev() {
assume!(i - limbs < LIMBS && i - limbs - 1 < LIMBS);
self.limbs[i] = self.limbs[i - limbs] << bits;
self.limbs[i] |= self.limbs[i - limbs - 1] >> (64 - bits);
}
self.limbs[limbs] = self.limbs[0] << bits;
for i in 0..limbs {
self.limbs[i] = 0;
}
self.limbs[..limbs].fill(0);
self.limbs[LIMBS - 1] &= Self::MASK;
(self, overflow)
}
Expand Down Expand Up @@ -367,9 +365,7 @@ impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
for i in 0..(LIMBS - limbs) {
self.limbs[i] = self.limbs[i + limbs];
}
for i in (LIMBS - limbs)..LIMBS {
self.limbs[i] = 0;
}
self.limbs[LIMBS - limbs..].fill(0);
return (self, overflow);
}

Expand All @@ -378,13 +374,12 @@ impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {

// Shift
for i in 0..(LIMBS - limbs - 1) {
assume!(i + limbs < LIMBS && i + limbs + 1 < LIMBS);
self.limbs[i] = self.limbs[i + limbs] >> bits;
self.limbs[i] |= self.limbs[i + limbs + 1] << (64 - bits);
}
self.limbs[LIMBS - limbs - 1] = self.limbs[LIMBS - 1] >> bits;
for i in (LIMBS - limbs)..LIMBS {
self.limbs[i] = 0;
}
self.limbs[LIMBS - limbs..].fill(0);
(self, overflow)
}

Expand Down Expand Up @@ -630,6 +625,7 @@ macro_rules! impl_shift {
type Output = Self;

#[inline(always)]
#[allow(clippy::cast_possible_truncation)]
fn shl(self, rhs: $u) -> Self::Output {
self.wrapping_shl(rhs as usize)
}
Expand All @@ -639,8 +635,9 @@ macro_rules! impl_shift {
type Output = Self;

#[inline(always)]
#[allow(clippy::cast_possible_truncation)]
fn shr(self, rhs: $u) -> Self::Output {
self.wrapping_shr(rhs as usize)
self.wrapping_shr(rhs as usize)
}
}
};
Expand Down
1 change: 1 addition & 0 deletions src/from.rs
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,7 @@ macro_rules! to_int {
type Error = FromUintError<Self>;

#[inline]
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
fn try_from(value: &Uint<BITS, LIMBS>) -> Result<Self, Self::Error> {
const SIGNED: bool = <$int>::MIN != 0;
const CAPACITY: usize = if SIGNED { <$int>::BITS - 1 } else { <$int>::BITS } as usize;
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
clippy::unreadable_literal,
clippy::let_unit_value,
clippy::option_if_let_else,
clippy::cast_sign_loss,
clippy::cast_lossless,
)]
#![cfg_attr(
any(test, feature = "bench"),
Expand Down
24 changes: 24 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,30 @@ macro_rules! impl_bin_op {
};
}

macro_rules! assume {
($e:expr $(,)?) => {
if !$e {
debug_unreachable!(stringify!($e));
}
};

($e:expr, $($t:tt)+) => {
if !$e {
debug_unreachable!($($t)+);
}
};
}

macro_rules! debug_unreachable {
($($t:tt)*) => {
if cfg!(debug_assertions) {
unreachable!($($t)*);
} else {
unsafe { core::hint::unreachable_unchecked() };
}
};
}

#[cfg(test)]
mod tests {
// https://github.com/recmo/uint/issues/359
Expand Down

0 comments on commit 46fc569

Please sign in to comment.