Index: llvm/trunk/include/llvm/Support/Alignment.h =================================================================== --- llvm/trunk/include/llvm/Support/Alignment.h +++ llvm/trunk/include/llvm/Support/Alignment.h @@ -58,10 +58,10 @@ constexpr Align() = default; /// Do not perform checks in case of copy/move construct/assign, because the /// checks have been performed when building `Other`. - Align(const Align &Other) = default; - Align &operator=(const Align &Other) = default; - Align(Align &&Other) = default; - Align &operator=(Align &&Other) = default; + constexpr Align(const Align &Other) = default; + constexpr Align &operator=(const Align &Other) = default; + constexpr Align(Align &&Other) = default; + constexpr Align &operator=(Align &&Other) = default; explicit Align(uint64_t Value) { assert(Value > 0 && "Value must not be 0"); @@ -80,6 +80,24 @@ /// would be better than /// `if (A > Align(1))` constexpr static const Align None() { return Align(); } + + /// This function is useful when initializing constexpr Align constants. + /// e.g. static constexpr Align kAlign16 = Align::Constant<16>(); + /// Most compilers (clang, gcc, icc) will be able to compute `ShiftValue` + /// at compile time with `Align::Align(uint64_t Value)` but to be + /// able to use Align as a constexpr constant use this method. + /// FIXME: When LLVM is C++17 ready `Align::Align(uint64_t Value)` + /// can be constexpr and we can dispatch between runtime (Log2_64) vs + /// compile time (CTLog2) versions using constexpr-if. Then this + /// function is no more necessary and we can add user defined literals + /// for convenience. + template constexpr static Align Constant() { + static_assert(kValue > 0 && llvm::isPowerOf2_64(kValue), + "Not a valid alignment"); + Align A; + A.ShiftValue = CTLog2(); + return A; + } }; /// Treats the value 0 as a 1, so Align is always at least 1. Index: llvm/trunk/include/llvm/Support/MathExtras.h =================================================================== --- llvm/trunk/include/llvm/Support/MathExtras.h +++ llvm/trunk/include/llvm/Support/MathExtras.h @@ -532,6 +532,15 @@ #endif } +/// Return the compile time log base 2 of the specified Value. +/// `kValue` has to be a power of two. +template static constexpr inline uint8_t CTLog2() { + static_assert(kValue > 0 && llvm::isPowerOf2_64(kValue), + "Value is not a valid power of 2"); + return 1 + CTLog2(); +} +template <> constexpr inline uint8_t CTLog2<1>() { return 0; } + /// Return the floor log base 2 of the specified value, -1 if the value is zero. /// (32 bit edition.) /// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2 Index: llvm/trunk/lib/Target/AArch64/AArch64StackTagging.cpp =================================================================== --- llvm/trunk/lib/Target/AArch64/AArch64StackTagging.cpp +++ llvm/trunk/lib/Target/AArch64/AArch64StackTagging.cpp @@ -62,7 +62,7 @@ static cl::opt ClScanLimit("stack-tagging-merge-init-scan-limit", cl::init(40), cl::Hidden); -static const Align kTagGranuleSize = Align(16); +static constexpr Align kTagGranuleSize = Align::Constant<16>(); namespace { Index: llvm/trunk/unittests/Support/AlignmentTest.cpp =================================================================== --- llvm/trunk/unittests/Support/AlignmentTest.cpp +++ llvm/trunk/unittests/Support/AlignmentTest.cpp @@ -44,6 +44,16 @@ } } +TEST(AlignmentTest, CompileTimeConstant) { + EXPECT_EQ(Align::Constant<1>(), Align(1)); + EXPECT_EQ(Align::Constant<2>(), Align(2)); + EXPECT_EQ(Align::Constant<4>(), Align(4)); + EXPECT_EQ(Align::Constant<8>(), Align(8)); + EXPECT_EQ(Align::Constant<16>(), Align(16)); + EXPECT_EQ(Align::Constant<32>(), Align(32)); + EXPECT_EQ(Align::Constant<64>(), Align(64)); +} + TEST(AlignmentTest, CheckMaybeAlignHasValue) { EXPECT_TRUE(MaybeAlign(1)); EXPECT_TRUE(MaybeAlign(1).hasValue()); Index: llvm/trunk/unittests/Support/MathExtrasTest.cpp =================================================================== --- llvm/trunk/unittests/Support/MathExtrasTest.cpp +++ llvm/trunk/unittests/Support/MathExtrasTest.cpp @@ -203,6 +203,25 @@ EXPECT_EQ(4U, PowerOf2Floor(7U)); } +TEST(MathExtras, CTLog2) { + EXPECT_EQ(CTLog2<1ULL << 0>(), 0); + EXPECT_EQ(CTLog2<1ULL << 1>(), 1); + EXPECT_EQ(CTLog2<1ULL << 2>(), 2); + EXPECT_EQ(CTLog2<1ULL << 3>(), 3); + EXPECT_EQ(CTLog2<1ULL << 4>(), 4); + EXPECT_EQ(CTLog2<1ULL << 5>(), 5); + EXPECT_EQ(CTLog2<1ULL << 6>(), 6); + EXPECT_EQ(CTLog2<1ULL << 7>(), 7); + EXPECT_EQ(CTLog2<1ULL << 8>(), 8); + EXPECT_EQ(CTLog2<1ULL << 9>(), 9); + EXPECT_EQ(CTLog2<1ULL << 10>(), 10); + EXPECT_EQ(CTLog2<1ULL << 11>(), 11); + EXPECT_EQ(CTLog2<1ULL << 12>(), 12); + EXPECT_EQ(CTLog2<1ULL << 13>(), 13); + EXPECT_EQ(CTLog2<1ULL << 14>(), 14); + EXPECT_EQ(CTLog2<1ULL << 15>(), 15); +} + TEST(MathExtras, ByteSwap_32) { EXPECT_EQ(0x44332211u, ByteSwap_32(0x11223344)); EXPECT_EQ(0xDDCCBBAAu, ByteSwap_32(0xAABBCCDD));