Skip to content

Commit

Permalink
Unify addcarry probing for x86_64/x86
Browse files Browse the repository at this point in the history
  • Loading branch information
cuviper committed Oct 30, 2020
1 parent 0cc50c9 commit e3971e6
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 27 deletions.
26 changes: 15 additions & 11 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,24 @@ fn main() {
autocfg::emit("u64_digit");
}
let ac = autocfg::new();
if ac.probe_path("std::convert::TryFrom") || ac.probe_path("core::convert::TryFrom") {
let std = if ac.probe_sysroot_crate("std") {
"std"
} else {
"core"
};
if ac.probe_path(&format!("{}::convert::TryFrom", std)) {
autocfg::emit("has_try_from");
}

if u64_digit
&& (ac.probe_path("core::arch::x86_64::_addcarry_u64")
|| ac.probe_path("std::arch::x86_64::_addcarry_u64"))
{
autocfg::emit("use_addcarry_u64");
} else if !u64_digit
&& (ac.probe_path("core::arch::x86_64::_addcarry_u32")
|| ac.probe_path("core::arch::x86::_addcarry_u32"))
{
autocfg::emit("use_addcarry_u32");
if let Ok(target_arch) = env::var("CARGO_CFG_TARGET_ARCH") {
if target_arch == "x86_64" || target_arch == "x86" {
let digit = if u64_digit { "u64" } else { "u32" };

let addcarry = format!("{}::arch::{}::_addcarry_{}", std, target_arch, digit);
if ac.probe_path(&addcarry) {
autocfg::emit("use_addcarry");
}
}
}

autocfg::rerun_path("build.rs");
Expand Down
46 changes: 30 additions & 16 deletions src/algorithms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ use core::iter::repeat;
use core::mem;
use num_traits::{One, PrimInt, Zero};

#[cfg(all(use_addcarry, target_arch = "x86_64"))]
use core::arch::x86_64 as arch;

#[cfg(all(use_addcarry, target_arch = "x86"))]
use core::arch::x86 as arch;

use crate::biguint::biguint_from_vec;
use crate::biguint::BigUint;

Expand All @@ -15,31 +21,35 @@ use crate::bigint::Sign::{Minus, NoSign, Plus};
use crate::big_digit::{self, BigDigit, DoubleBigDigit};

// only needed for the fallback implementation of `sbb`
#[cfg(not(any(use_addcarry_u64, use_addcarry_u32)))]
#[cfg(not(use_addcarry))]
use crate::big_digit::SignedDoubleBigDigit;

// Generic functions for add/subtract/multiply with carry/borrow. These are specialized for some platforms to take advantage of intrinsics etc
// Generic functions for add/subtract/multiply with carry/borrow. These are specialized
// for some platforms to take advantage of intrinsics, etc.

// Add with carry:
#[cfg(use_addcarry_u64)]
#[cfg(all(use_addcarry, u64_digit))]
#[inline]
fn adc(a: BigDigit, b: BigDigit, acc: &mut u8) -> BigDigit {
let mut out = 0;
// Safety: There are absolutely no safety concerns with calling _addcarry_u64, it's just unsafe for API consistency with other intrinsics
*acc = unsafe { core::arch::x86_64::_addcarry_u64(*acc, a, b, &mut out) };
// Safety: There are absolutely no safety concerns with calling `_addcarry_u64`.
// It's just unsafe for API consistency with other intrinsics.
*acc = unsafe { arch::_addcarry_u64(*acc, a, b, &mut out) };
out
}

#[cfg(use_addcarry_u32)]
#[cfg(all(use_addcarry, not(u64_digit)))]
#[inline]
fn adc(a: BigDigit, b: BigDigit, acc: &mut u8) -> BigDigit {
let mut out = 0;
// Safety: There are absolutely no safety concerns with calling _addcarry_u32, it's just unsafe for API consistency with other intrinsics
*acc = unsafe { core::arch::x86_64::_addcarry_u32(*acc, a, b, &mut out) };
// Safety: There are absolutely no safety concerns with calling `_addcarry_u32`.
// It's just unsafe for API consistency with other intrinsics.
*acc = unsafe { arch::_addcarry_u32(*acc, a, b, &mut out) };
out
}

#[cfg(not(any(use_addcarry_u64, use_addcarry_u32)))] // fallback for environments where we don't have an addcarry intrinsic
// fallback for environments where we don't have an addcarry intrinsic
#[cfg(not(use_addcarry))]
#[inline]
fn adc(a: BigDigit, b: BigDigit, acc: &mut DoubleBigDigit) -> BigDigit {
*acc += DoubleBigDigit::from(a);
Expand All @@ -50,24 +60,28 @@ fn adc(a: BigDigit, b: BigDigit, acc: &mut DoubleBigDigit) -> BigDigit {
}

// Subtract with borrow:
#[cfg(use_addcarry_u64)]
#[cfg(all(use_addcarry, u64_digit))]
#[inline]
fn sbb(a: BigDigit, b: BigDigit, acc: &mut u8) -> BigDigit {
let mut out = 0;
// Safety: There are absolutely no safety concerns with calling _subborrow_u64, it's just unsafe for API consistency with other intrinsics
*acc = unsafe { core::arch::x86_64::_subborrow_u64(*acc, a, b, &mut out) };
// Safety: There are absolutely no safety concerns with calling `_subborrow_u64`.
// It's just unsafe for API consistency with other intrinsics.
*acc = unsafe { arch::_subborrow_u64(*acc, a, b, &mut out) };
out
}
#[cfg(use_addcarry_u32)]

#[cfg(all(use_addcarry, not(u64_digit)))]
#[inline]
fn sbb(a: BigDigit, b: BigDigit, acc: &mut u8) -> BigDigit {
let mut out = 0;
// Safety: There are absolutely no safety concerns with calling _subborrow_u32, it's just unsafe for API consistency with other intrinsics
*acc = unsafe { core::arch::x86_64::_subborrow_u32(*acc, a, b, &mut out) };
// Safety: There are absolutely no safety concerns with calling `_subborrow_u32`.
// It's just unsafe for API consistency with other intrinsics.
*acc = unsafe { arch::_subborrow_u32(*acc, a, b, &mut out) };
out
}

#[cfg(not(any(use_addcarry_u64, use_addcarry_u32)))] // fallback for environments where we don't have an addcarry intrinsic
// fallback for environments where we don't have an addcarry intrinsic
#[cfg(not(use_addcarry))]
#[inline]
fn sbb(a: BigDigit, b: BigDigit, acc: &mut SignedDoubleBigDigit) -> BigDigit {
*acc += SignedDoubleBigDigit::from(a);
Expand Down

0 comments on commit e3971e6

Please sign in to comment.