diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h --- a/llvm/include/llvm/ADT/APInt.h +++ b/llvm/include/llvm/ADT/APInt.h @@ -28,6 +28,8 @@ class StringRef; class hash_code; class raw_ostream; +struct Align; +unsigned Log2(const Align &); template class SmallVectorImpl; template class ArrayRef; @@ -433,6 +435,16 @@ return (LO + TZ) == BitWidth; } + /// Checks if this APInt -interpreted as an address- is aligned to the + /// provided value. + bool isAligned(const Align &A) const { + if (isZero()) + return true; + const unsigned TrailingZeroes = countr_zero(); + const unsigned MinimumTrailingZeroes = Log2(A); + return TrailingZeroes >= MinimumTrailingZeroes; + } + /// Check if the APInt's value is returned by getSignMask. /// /// \returns true if this is the value returned by getSignMask. @@ -1570,8 +1582,8 @@ /// Count the number of trailing zero bits. /// - /// This function is an APInt version of std::countr_zero. It counts the number - /// of zeros from the least significant bit to the first set bit. + /// This function is an APInt version of std::countr_zero. It counts the + /// number of zeros from the least significant bit to the first set bit. /// /// \returns BitWidth if the value is zero, otherwise returns the number of /// zeros from the least significant bit to the first one bit. diff --git a/llvm/include/llvm/Support/Alignment.h b/llvm/include/llvm/Support/Alignment.h --- a/llvm/include/llvm/Support/Alignment.h +++ b/llvm/include/llvm/Support/Alignment.h @@ -42,7 +42,7 @@ /// ShiftValue is less than 64 by construction. friend struct MaybeAlign; - friend unsigned Log2(Align); + friend unsigned Log2(const Align &); friend bool operator==(Align Lhs, Align Rhs); friend bool operator!=(Align Lhs, Align Rhs); friend bool operator<=(Align Lhs, Align Rhs); @@ -205,7 +205,7 @@ } /// Returns the log2 of the alignment. -inline unsigned Log2(Align A) { return A.ShiftValue; } +inline unsigned Log2(const Align &A) { return A.ShiftValue; } /// Returns the alignment that satisfies both alignments. /// Same semantic as MinAlign. diff --git a/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp --- a/llvm/unittests/ADT/APIntTest.cpp +++ b/llvm/unittests/ADT/APIntTest.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/Alignment.h" #include "gtest/gtest.h" #include #include @@ -1852,6 +1853,25 @@ } } +TEST(APIntTest, isAligned) { + struct { + uint64_t alignment; + uint64_t offset; + bool isAligned; + } kTests[] = { + {1, 0, true}, {1, 1, true}, {1, 5, true}, {2, 0, true}, + {2, 1, false}, {2, 2, true}, {2, 7, false}, {2, 16, true}, + {4, 0, true}, {4, 1, false}, {4, 4, true}, {4, 6, false}, + }; + for (const auto &T : kTests) + EXPECT_EQ(APInt(32, T.offset).isAligned(Align(T.alignment)), T.isAligned); + // Tests for APInt that can't represent the alignment. + // Here APInt(4, I) can represent values from 0 to 15. + EXPECT_TRUE(APInt(4, 0).isAligned(Align(32))); // zero is always aligned. + for (int I = 1; I < 16; ++I) + EXPECT_FALSE(APInt(4, I).isAligned(Align(32))); +} + // Test that self-move works with EXPENSIVE_CHECKS. It calls std::shuffle which // does self-move on some platforms. #ifdef EXPENSIVE_CHECKS