Expand description

This specialized_div_rem module is originally from version 1.0.0 of the specialized-div-rem crate. Note that for loops with ranges are not used in this module, since unoptimized compilation may generate references to memcpy.

The purpose of these macros is to easily change the both the division algorithm used for a given integer size and the half division used by that algorithm. The way functions call each other is also constructed such that linkers will find the chain of software and hardware divisions needed for every size of signed and unsigned division. For example, most target compilations do the following:

  • Many 128 bit division functions like u128::wrapping_div use std::intrinsics::unchecked_div, which gets replaced by __udivti3 because there is not a 128 bit by 128 bit hardware division function in most architectures. __udivti3 uses u128_div_rem (this extra level of function calls exists because __umodti3 and __udivmodti4 also exist, and specialized_div_rem supplies just one function to calculate both the quotient and remainder. If configuration flags enable it, impl_trifecta! defines u128_div_rem to use the trifecta algorithm, which requires the half sized division u64_by_u64_div_rem. If the architecture supplies a 64 bit hardware division instruction, u64_by_u64_div_rem will be reduced to those instructions. Note that we do not specify the half size division directly to be __udivdi3, because hardware division would never be introduced.
  • If the architecture does not supply a 64 bit hardware division instruction, u64 divisions will use functions such as __udivdi3. This will call u64_div_rem which is defined by impl_delegate!. The half division for this algorithm is u32_by_u32_div_rem which in turn becomes hardware division instructions or more software division algorithms.
  • If the architecture does not supply a 32 bit hardware instruction, linkers will look for __udivsi3. impl_binary_long! is used, but this algorithm uses no half division, so the chain of calls ends here.

On some architectures like x86_64, an asymmetrically sized division is supplied, in which 128 bit numbers can be divided by 64 bit numbers. impl_asymmetric! is used to extend the 128 by 64 bit division to a full 128 by 128 bit division.

Modules

Constants

Functions

  • Divides duo by div and returns a tuple of the quotient and the remainder. checked_div and checked_rem are used to avoid bringing in panic function dependencies.
  • Computes the quotient and remainder of duo divided by div and returns them as a tuple.
  • Finds the shift left that the divisor div would need to be normalized for a binary long division step with the dividend duo. NOTE: This function assumes that these edge cases have been handled before reaching it: if div == 0 { panic!("attempt to divide by zero") } if duo < div { return (0, duo) }
  • Divides duo by div and returns a tuple of the quotient and the remainder. checked_div and checked_rem are used to avoid bringing in panic function dependencies.
  • Computes the quotient and remainder of duo divided by div and returns them as a tuple.
  • Finds the shift left that the divisor div would need to be normalized for a binary long division step with the dividend duo. NOTE: This function assumes that these edge cases have been handled before reaching it: if div == 0 { panic!("attempt to divide by zero") } if duo < div { return (0, duo) }
  • Divides duo by div and returns a tuple of the quotient and the remainder.
  • Computes the quotient and remainder of duo divided by div and returns them as a tuple.
  • The behavior of all divisions by zero is controlled by this function. This function should be impossible to reach by Rust users, unless compiler-builtins public division functions or core/std::unchecked_div/rem are directly used without a zero check in front.