diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h index 6a08e6eed53de1..07b2e80099e64d 100644 --- a/llvm/include/llvm/ADT/APInt.h +++ b/llvm/include/llvm/ADT/APInt.h @@ -2220,6 +2220,12 @@ APInt RoundingSDiv(const APInt &A, const APInt &B, APInt::Rounding RM); /// coefficients. Optional SolveQuadraticEquationWrap(APInt A, APInt B, APInt C, unsigned RangeWidth); + +/// Compare two values, and if they are different, return the position of the +/// most significant bit that is different in the values. +Optional GetMostSignificantDifferentBit(const APInt &A, + const APInt &B); + } // End of APIntOps namespace // See friend declaration above. This additional declaration is required in diff --git a/llvm/lib/Support/APInt.cpp b/llvm/lib/Support/APInt.cpp index 08e9757702af1a..5f2686c4055c01 100644 --- a/llvm/lib/Support/APInt.cpp +++ b/llvm/lib/Support/APInt.cpp @@ -3027,6 +3027,14 @@ llvm::APIntOps::SolveQuadraticEquationWrap(APInt A, APInt B, APInt C, return X; } +Optional +llvm::APIntOps::GetMostSignificantDifferentBit(const APInt &A, const APInt &B) { + assert(A.getBitWidth() == B.getBitWidth() && "Must have the same bitwidth"); + if (A == B) + return llvm::None; + return A.getBitWidth() - ((A ^ B).countLeadingZeros() + 1); +} + /// StoreIntToMemory - Fills the StoreBytes bytes of memory starting from Dst /// with the integer held in IntVal. void llvm::StoreIntToMemory(const APInt &IntVal, uint8_t *Dst, diff --git a/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp index 5130b9420d67dd..fe4e7426099021 100644 --- a/llvm/unittests/ADT/APIntTest.cpp +++ b/llvm/unittests/ADT/APIntTest.cpp @@ -2723,4 +2723,75 @@ TEST(APIntTest, MultiplicativeInverseExaustive) { } } +TEST(APIntTest, GetMostSignificantDifferentBit) { + EXPECT_EQ(APIntOps::GetMostSignificantDifferentBit(APInt(8, 0), APInt(8, 0)), + llvm::None); + EXPECT_EQ( + APIntOps::GetMostSignificantDifferentBit(APInt(8, 42), APInt(8, 42)), + llvm::None); + EXPECT_EQ(*APIntOps::GetMostSignificantDifferentBit(APInt(8, 0), APInt(8, 1)), + 0u); + EXPECT_EQ(*APIntOps::GetMostSignificantDifferentBit(APInt(8, 0), APInt(8, 2)), + 1u); + EXPECT_EQ(*APIntOps::GetMostSignificantDifferentBit(APInt(8, 0), APInt(8, 3)), + 1u); + EXPECT_EQ(*APIntOps::GetMostSignificantDifferentBit(APInt(8, 1), APInt(8, 0)), + 0u); + EXPECT_EQ(APIntOps::GetMostSignificantDifferentBit(APInt(8, 1), APInt(8, 1)), + llvm::None); + EXPECT_EQ(*APIntOps::GetMostSignificantDifferentBit(APInt(8, 1), APInt(8, 2)), + 1u); + EXPECT_EQ(*APIntOps::GetMostSignificantDifferentBit(APInt(8, 1), APInt(8, 3)), + 1u); + EXPECT_EQ( + *APIntOps::GetMostSignificantDifferentBit(APInt(8, 42), APInt(8, 112)), + 6u); +} + +TEST(APIntTest, GetMostSignificantDifferentBitExaustive) { + auto GetHighestDifferentBitBruteforce = + [](const APInt &V0, const APInt &V1) -> llvm::Optional { + assert(V0.getBitWidth() == V1.getBitWidth() && "Must have same bitwidth"); + if (V0 == V1) + return llvm::None; // Bitwise identical. + // There is a mismatch. Let's find the most significant different bit. + for (int Bit = V0.getBitWidth() - 1; Bit >= 0; --Bit) { + if (V0[Bit] == V1[Bit]) + continue; + return Bit; + } + llvm_unreachable("Must have found bit mismatch."); + }; + + for (unsigned BitWidth = 1; BitWidth <= 8; ++BitWidth) { + for (unsigned V0 = 0; V0 < (1u << BitWidth); ++V0) { + for (unsigned V1 = 0; V1 < (1u << BitWidth); ++V1) { + APInt A = APInt(BitWidth, V0); + APInt B = APInt(BitWidth, V1); + + auto Bit = APIntOps::GetMostSignificantDifferentBit(A, B); + EXPECT_EQ(Bit, GetHighestDifferentBitBruteforce(A, B)); + + if (!Bit.hasValue()) + EXPECT_EQ(A, B); + else { + EXPECT_NE(A, B); + for (unsigned NumLowBits = 0; NumLowBits <= BitWidth; ++NumLowBits) { + APInt Adash = A; + Adash.clearLowBits(NumLowBits); + APInt Bdash = B; + Bdash.clearLowBits(NumLowBits); + // Clearing only low bits up to and including *Bit is sufficient + // to make values equal. + if (NumLowBits >= 1 + *Bit) + EXPECT_EQ(Adash, Bdash); + else + EXPECT_NE(Adash, Bdash); + } + } + } + } + } +} + } // end anonymous namespace