]> granicus.if.org Git - llvm/commitdiff
[Alignment][NFC] Support compile time constants
authorGuillaume Chatelet <gchatelet@google.com>
Mon, 14 Oct 2019 09:04:15 +0000 (09:04 +0000)
committerGuillaume Chatelet <gchatelet@google.com>
Mon, 14 Oct 2019 09:04:15 +0000 (09:04 +0000)
Summary:
This is patch is part of a series to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790

Reviewers: courbet

Subscribers: llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D68936

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@374758 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Support/Alignment.h
include/llvm/Support/MathExtras.h
unittests/Support/AlignmentTest.cpp
unittests/Support/MathExtrasTest.cpp

index 3d8a4235b0e654ad5fb677b43eb32fab82734cb3..5e8e686150d26b402df5419149022cad9145cf76 100644 (file)
@@ -53,14 +53,25 @@ private:
   friend unsigned encode(struct MaybeAlign A);
   friend struct MaybeAlign decodeMaybeAlign(unsigned Value);
 
+  /// A trivial type to allow construction of constexpr Align.
+  /// This is currently needed to workaround a bug in GCC 5.3 which prevents
+  /// definition of constexpr assign operators.
+  /// https://stackoverflow.com/questions/46756288/explicitly-defaulted-function-cannot-be-declared-as-constexpr-because-the-implic
+  /// FIXME: Remove this, make all assign operators constexpr and introduce user
+  /// defined literals when we don't have to support GCC 5.3 anymore.
+  /// https://llvm.org/docs/GettingStarted.html#getting-a-modern-host-c-toolchain
+  struct LogValue {
+    uint8_t Log;
+  };
+
 public:
   /// Default is byte-aligned.
   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;
+  constexpr Align(const Align &Other) = default;
+  constexpr Align(Align &&Other) = default;
   Align &operator=(const Align &Other) = default;
-  Align(Align &&Other) = default;
   Align &operator=(Align &&Other) = default;
 
   explicit Align(uint64_t Value) {
@@ -80,6 +91,20 @@ public:
   /// would be better than
   /// `if (A > Align(1))`
   constexpr static const Align None() { return Align(); }
+
+  /// Allow constructions of constexpr Align.
+  template <size_t kValue> constexpr static LogValue Constant() {
+    return LogValue{CTLog2<kValue>()};
+  }
+
+  /// Allow constructions of constexpr Align from types.
+  /// Compile time equivalent to Align(alignof(T)).
+  template <typename T> constexpr static LogValue Of() {
+    return Constant<std::alignment_of<T>::value>();
+  }
+
+  /// Constexpr constructor from LogValue type.
+  constexpr Align(LogValue CA) : ShiftValue(CA.Log) {}
 };
 
 /// Treats the value 0 as a 1, so Align is always at least 1.
index 605539ea11e24d369db9ba61ffbffcd3145557b1..be6152a19b8b58d0c3b3b2723b200349d21fda2b 100644 (file)
@@ -560,6 +560,16 @@ inline unsigned countPopulation(T Value) {
   return detail::PopulationCounter<T, sizeof(T)>::count(Value);
 }
 
+/// Compile time Log2.
+/// Valid only for positive powers of two.
+template <size_t kValue> constexpr inline size_t CTLog2() {
+  static_assert(kValue > 0 && llvm::isPowerOf2_64(kValue),
+                "Value is not a valid power of 2");
+  return 1 + CTLog2<kValue / 2>();
+}
+
+template <> constexpr inline size_t CTLog2<1>() { return 0; }
+
 /// Return the log base 2 of the specified value.
 inline double Log2(double Value) {
 #if defined(__ANDROID_API__) && __ANDROID_API__ < 18
index 0b1435912b93020bd576007a89126f4645952fc9..a6c053385cbb7a921bdbcaae1402d2d76192cefc 100644 (file)
@@ -21,6 +21,28 @@ using namespace llvm;
 
 namespace {
 
+TEST(AlignmentTest, AlignOfConstant) {
+  EXPECT_EQ(Align::Of<uint8_t>(), Align(alignof(uint8_t)));
+  EXPECT_EQ(Align::Of<uint16_t>(), Align(alignof(uint16_t)));
+  EXPECT_EQ(Align::Of<uint32_t>(), Align(alignof(uint32_t)));
+  EXPECT_EQ(Align::Of<uint64_t>(), Align(alignof(uint64_t)));
+}
+
+TEST(AlignmentTest, AlignConstant) {
+  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, AlignConstexprConstant) {
+  constexpr Align kConstantAlign = Align::Of<uint64_t>();
+  EXPECT_EQ(Align(8), kConstantAlign);
+}
+
 std::vector<uint64_t> getValidAlignments() {
   std::vector<uint64_t> Out;
   for (size_t Shift = 0; Shift < 64; ++Shift)
index 01c83c9e14d3f7250af93ff88d562446d7f5c0fc..e910d83b626a0965d782857b62fea2318f1a0647 100644 (file)
@@ -203,6 +203,25 @@ TEST(MathExtras, PowerOf2Floor) {
   EXPECT_EQ(4U, PowerOf2Floor(7U));
 }
 
+TEST(MathExtras, CTLog2) {
+  EXPECT_EQ(CTLog2<1ULL << 0>(), 0U);
+  EXPECT_EQ(CTLog2<1ULL << 1>(), 1U);
+  EXPECT_EQ(CTLog2<1ULL << 2>(), 2U);
+  EXPECT_EQ(CTLog2<1ULL << 3>(), 3U);
+  EXPECT_EQ(CTLog2<1ULL << 4>(), 4U);
+  EXPECT_EQ(CTLog2<1ULL << 5>(), 5U);
+  EXPECT_EQ(CTLog2<1ULL << 6>(), 6U);
+  EXPECT_EQ(CTLog2<1ULL << 7>(), 7U);
+  EXPECT_EQ(CTLog2<1ULL << 8>(), 8U);
+  EXPECT_EQ(CTLog2<1ULL << 9>(), 9U);
+  EXPECT_EQ(CTLog2<1ULL << 10>(), 10U);
+  EXPECT_EQ(CTLog2<1ULL << 11>(), 11U);
+  EXPECT_EQ(CTLog2<1ULL << 12>(), 12U);
+  EXPECT_EQ(CTLog2<1ULL << 13>(), 13U);
+  EXPECT_EQ(CTLog2<1ULL << 14>(), 14U);
+  EXPECT_EQ(CTLog2<1ULL << 15>(), 15U);
+}
+
 TEST(MathExtras, ByteSwap_32) {
   EXPECT_EQ(0x44332211u, ByteSwap_32(0x11223344));
   EXPECT_EQ(0xDDCCBBAAu, ByteSwap_32(0xAABBCCDD));