Skip to content

[APInt] Remove multiplicativeInverse with explicit modulus #87644

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 4, 2024
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
3 changes: 0 additions & 3 deletions llvm/include/llvm/ADT/APInt.h
Original file line number Diff line number Diff line change
Expand Up @@ -1740,9 +1740,6 @@ class [[nodiscard]] APInt {
return *this;
}

/// \returns the multiplicative inverse for a given modulo.
APInt multiplicativeInverse(const APInt &modulo) const;

/// \returns the multiplicative inverse of an odd APInt modulo 2^BitWidth.
APInt multiplicativeInverse() const;

Expand Down
49 changes: 0 additions & 49 deletions llvm/lib/Support/APInt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1240,55 +1240,6 @@ APInt APInt::sqrt() const {
return x_old + 1;
}

/// Computes the multiplicative inverse of this APInt for a given modulo. The
/// iterative extended Euclidean algorithm is used to solve for this value,
/// however we simplify it to speed up calculating only the inverse, and take
/// advantage of div+rem calculations. We also use some tricks to avoid copying
/// (potentially large) APInts around.
/// WARNING: a value of '0' may be returned,
/// signifying that no multiplicative inverse exists!
APInt APInt::multiplicativeInverse(const APInt& modulo) const {
assert(ult(modulo) && "This APInt must be smaller than the modulo");

// Using the properties listed at the following web page (accessed 06/21/08):
// http://www.numbertheory.org/php/euclid.html
// (especially the properties numbered 3, 4 and 9) it can be proved that
// BitWidth bits suffice for all the computations in the algorithm implemented
// below. More precisely, this number of bits suffice if the multiplicative
// inverse exists, but may not suffice for the general extended Euclidean
// algorithm.

APInt r[2] = { modulo, *this };
APInt t[2] = { APInt(BitWidth, 0), APInt(BitWidth, 1) };
APInt q(BitWidth, 0);

unsigned i;
for (i = 0; r[i^1] != 0; i ^= 1) {
// An overview of the math without the confusing bit-flipping:
// q = r[i-2] / r[i-1]
// r[i] = r[i-2] % r[i-1]
// t[i] = t[i-2] - t[i-1] * q
udivrem(r[i], r[i^1], q, r[i]);
t[i] -= t[i^1] * q;
}

// If this APInt and the modulo are not coprime, there is no multiplicative
// inverse, so return 0. We check this by looking at the next-to-last
// remainder, which is the gcd(*this,modulo) as calculated by the Euclidean
// algorithm.
if (r[i] != 1)
return APInt(BitWidth, 0);

// The next-to-last t is the multiplicative inverse. However, we are
// interested in a positive inverse. Calculate a positive one from a negative
// one if necessary. A simple addition of the modulo suffices because
// abs(t[i]) is known to be less than *this/2 (see the link above).
if (t[i].isNegative())
t[i] += modulo;

return std::move(t[i]);
}

/// \returns the multiplicative inverse of an odd APInt modulo 2^BitWidth.
APInt APInt::multiplicativeInverse() const {
assert((*this)[0] &&
Expand Down
19 changes: 4 additions & 15 deletions llvm/unittests/ADT/APIntTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3249,22 +3249,11 @@ TEST(APIntTest, SolveQuadraticEquationWrap) {
}

TEST(APIntTest, MultiplicativeInverseExaustive) {
for (unsigned BitWidth = 1; BitWidth <= 16; ++BitWidth) {
for (unsigned Value = 0; Value < (1u << BitWidth); ++Value) {
for (unsigned BitWidth = 1; BitWidth <= 8; ++BitWidth) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Testing 8 different bitwidths seems exhaustive enough to me.

for (unsigned Value = 1; Value < (1u << BitWidth); Value += 2) {
// Multiplicative inverse exists for all odd numbers.
APInt V = APInt(BitWidth, Value);
APInt MulInv =
V.zext(BitWidth + 1)
.multiplicativeInverse(APInt::getSignedMinValue(BitWidth + 1))
.trunc(BitWidth);
APInt One = V * MulInv;
if (V[0]) {
// Multiplicative inverse exists for all odd numbers.
EXPECT_TRUE(One.isOne());
EXPECT_TRUE((V * V.multiplicativeInverse()).isOne());
} else {
// Multiplicative inverse does not exist for even numbers (and 0).
EXPECT_TRUE(MulInv.isZero());
}
EXPECT_EQ(V * V.multiplicativeInverse(), 1);
}
}
}
Expand Down