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 @@ -164,17 +164,34 @@ /// Returns a multiple of A needed to store `Size` bytes. inline uint64_t alignTo(uint64_t Size, Align A) { - const uint64_t value = A.value(); - // The following line is equivalent to `(Size + value - 1) / value * value`. + const uint64_t Value = A.value(); + // The following line is equivalent to `(Size + Value - 1) / Value * Value`. // The division followed by a multiplication can be thought of as a right // shift followed by a left shift which zeros out the extra bits produced in - // the bump; `~(value - 1)` is a mask where all those bits being zeroed out + // the bump; `~(Value - 1)` is a mask where all those bits being zeroed out // are just zero. // Most compilers can generate this code but the pattern may be missed when // multiple functions gets inlined. - return (Size + value - 1) & ~(value - 1); + return (Size + Value - 1) & ~(Value - 1U); +} + +/// If non-zero \p Skew is specified, the return value will be a minimal integer +/// that is greater than or equal to \p Size and equal to \p A * N + \p Skew for +/// some integer N. If \p Skew is larger than \p A, its value is adjusted to '\p +/// Skew mod \p A'. +/// +/// Examples: +/// \code +/// alignTo(5, Align(8), 7) = 7 +/// alignTo(17, Align(8), 1) = 17 +/// alignTo(~0LL, Align(8), 3) = 3 +/// \endcode +inline uint64_t alignTo(uint64_t Size, Align A, uint64_t Skew) { + const uint64_t Value = A.value(); + Skew %= Value; + return ((Size + Value - 1 - Skew) & ~(Value - 1U)) + Skew; } /// Returns a multiple of A needed to store `Size` bytes. diff --git a/llvm/unittests/Support/AlignmentTest.cpp b/llvm/unittests/Support/AlignmentTest.cpp --- a/llvm/unittests/Support/AlignmentTest.cpp +++ b/llvm/unittests/Support/AlignmentTest.cpp @@ -125,6 +125,13 @@ } } +TEST(AlignmentTest, AlignToWithSkew) { + EXPECT_EQ(alignTo(5, Align(8), 0), alignTo(5, Align(8))); + EXPECT_EQ(alignTo(5, Align(8), 7), 7U); + EXPECT_EQ(alignTo(17, Align(8), 1), 17U); + EXPECT_EQ(alignTo(~0LL, Align(8), 3), 3U); +} + TEST(AlignmentTest, Log2) { for (uint64_t Value : getValidAlignments()) { EXPECT_EQ(Log2(Align(Value)), Log2_64(Value));