Skip to content

Commit 7dd6340

Browse files
authored
MathExtras: template'ize alignToPowerOf2 (#97814)
Follow up on 5627794 (MathExtras: avoid unnecessarily widening types) to change the overflow behavior of alignToPowerOf2 to only overflow if the result is not representable in the return type. This allows us to template'ize it, and avoid unnecessarily widening the types of arguments.
1 parent a566635 commit 7dd6340

File tree

2 files changed

+17
-6
lines changed

2 files changed

+17
-6
lines changed

llvm/include/llvm/Support/MathExtras.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -497,13 +497,21 @@ constexpr uint64_t alignTo(uint64_t Value, uint64_t Align) {
497497
return CeilDiv * Align;
498498
}
499499

500+
/// Will overflow only if result is not representable in T.
501+
template <typename U, typename V, typename T = common_uint<U, V>>
502+
constexpr T alignToPowerOf2(U Value, V Align) {
503+
assert(Align != 0 && (Align & (Align - 1)) == 0 &&
504+
"Align must be a power of 2");
505+
T NegAlign = static_cast<T>(0) - Align;
506+
return (Value + (Align - 1)) & NegAlign;
507+
}
508+
509+
/// Fallback when arguments aren't integral.
500510
constexpr uint64_t alignToPowerOf2(uint64_t Value, uint64_t Align) {
501511
assert(Align != 0 && (Align & (Align - 1)) == 0 &&
502512
"Align must be a power of 2");
503-
// Replace unary minus to avoid compilation error on Windows:
504-
// "unary minus operator applied to unsigned type, result still unsigned"
505-
uint64_t NegAlign = (~Align) + 1;
506-
return (Value + Align - 1) & NegAlign;
513+
uint64_t NegAlign = 0 - Align;
514+
return (Value + (Align - 1)) & NegAlign;
507515
}
508516

509517
/// If non-zero \p Skew is specified, the return value will be a minimal integer

llvm/unittests/Support/MathExtrasTest.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,11 @@ TEST(MathExtras, AlignToPowerOf2) {
218218
EXPECT_EQ(24u, alignToPowerOf2(17, 8));
219219
EXPECT_EQ(0u, alignToPowerOf2(~0LL, 8));
220220
EXPECT_EQ(240u, alignToPowerOf2(240, 16));
221-
EXPECT_EQ(static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()) + 1,
222-
alignToPowerOf2(std::numeric_limits<uint32_t>::max(), 2));
221+
222+
// Overflow.
223+
EXPECT_EQ(0u, alignToPowerOf2(static_cast<uint8_t>(200),
224+
static_cast<uint8_t>(128)));
225+
EXPECT_EQ(0u, alignToPowerOf2(std::numeric_limits<uint32_t>::max(), 2));
223226
}
224227

225228
TEST(MathExtras, AlignDown) {

0 commit comments

Comments
 (0)