[llvm] [CHERI] Add a Support utility for determining alignment requirements of CHERI capabilities. (PR #197402)

Owen Anderson via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 1 08:04:47 PDT 2026


https://github.com/resistor updated https://github.com/llvm/llvm-project/pull/197402

>From 41338f1eeb5e9fdcca77bc1761a1888104d3007a Mon Sep 17 00:00:00 2001
From: Owen Anderson <resistor at mac.com>
Date: Wed, 13 May 2026 11:45:22 +0200
Subject: [PATCH 1/2] [CHERI] Add a Support utility for determining alignment
 requirements of CHERI capabilities.

On CHERI systems with compressed bounds representations (which is all of them that anyone cares about today), one of the tradeoffs to achieve that compression is a requirement for larger allocations to be more highly aligned. This impacts both code generation and linking in places where globals need to be aligned and/or padded based on this requirement. The specific alignment requirements vary by capability format.

This utility provides an extensible means of representing the typical alignment-related queries using a single LUT per capability format. These LUT tables were verified against the equivalent queries against the cheri-compressed-cap reference "soft" capability implementation.
---
 .../llvm/Support/CHERICapabilityFormat.h      |  60 ++++++++
 llvm/lib/Support/CHERICapabilityFormat.cpp    | 134 ++++++++++++++++++
 llvm/lib/Support/CMakeLists.txt               |   1 +
 .../Support/CHERICapabilityFormatTest.cpp     |  91 ++++++++++++
 llvm/unittests/Support/CMakeLists.txt         |   1 +
 5 files changed, 287 insertions(+)
 create mode 100644 llvm/include/llvm/Support/CHERICapabilityFormat.h
 create mode 100644 llvm/lib/Support/CHERICapabilityFormat.cpp
 create mode 100644 llvm/unittests/Support/CHERICapabilityFormatTest.cpp

diff --git a/llvm/include/llvm/Support/CHERICapabilityFormat.h b/llvm/include/llvm/Support/CHERICapabilityFormat.h
new file mode 100644
index 0000000000000..f3a0ca2c87bbe
--- /dev/null
+++ b/llvm/include/llvm/Support/CHERICapabilityFormat.h
@@ -0,0 +1,60 @@
+//===--- CHERICapabilityFormat.h --------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CHERICAPABILITYFORMAT_H
+#define LLVM_SUPPORT_CHERICAPABILITYFORMAT_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Alignment.h"
+
+#include <algorithm>
+
+namespace llvm {
+
+class CHERICapabilityFormat {
+  constexpr CHERICapabilityFormat(uint64_t AM,
+                                  ArrayRef<std::pair<uint64_t, uint64_t>> L)
+      : AddressMask(AM), LUT(L) {}
+
+  uint64_t AddressMask;
+  ArrayRef<std::pair<uint64_t, uint64_t>> LUT;
+
+public:
+  /// Returns the mask for the address bits in the capability.
+  uint64_t getAddressMask() const { return AddressMask; }
+
+  /// Returns the "alignment mask" for an allocation of size \p Length. This
+  /// mask is 0 where the capability format alignment requirements for the
+  /// address to be 0, and 1 otherwise.
+  uint64_t getAlignmentMask(uint64_t Length) const {
+    auto el = std::find_if(LUT.begin(), LUT.end(),
+                           [=](const auto &p) { return Length <= p.first; });
+    assert(el != LUT.end() && "Could not find alignment mask for length!");
+    return el->second;
+  }
+
+  /// Returns the required alignment for an allocation of size \p Length.
+  Align getRequiredAlignment(uint64_t Length) const {
+    return Align((~getAlignmentMask(Length) + 1) & getAddressMask());
+  }
+
+  /// Returns \p Length rounded up to the nearest representable allocation
+  /// length.
+  uint64_t getRepresentableLength(uint64_t Length) const {
+    uint64_t Mask = getAlignmentMask(Length);
+    return (Length + ~Mask) & Mask;
+  }
+
+  static const CHERICapabilityFormat Cheriot64;
+  static const CHERICapabilityFormat Cheri64;
+  static const CHERICapabilityFormat Cheri128;
+};
+
+} // namespace llvm
+
+#endif
diff --git a/llvm/lib/Support/CHERICapabilityFormat.cpp b/llvm/lib/Support/CHERICapabilityFormat.cpp
new file mode 100644
index 0000000000000..e055b716578e5
--- /dev/null
+++ b/llvm/lib/Support/CHERICapabilityFormat.cpp
@@ -0,0 +1,134 @@
+//===- CHERICapabilityFormat.cpp ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/CHERICapabilityFormat.h"
+
+namespace {
+
+constexpr std::pair<uint64_t, uint64_t> Cheri64AlignmentMasks[] = {
+    {0x000000000000003F, 0x00000000FFFFFFFF},
+    {0x0000000000000078, 0x00000000FFFFFFF8},
+    {0x00000000000000F0, 0x00000000FFFFFFF0},
+    {0x00000000000001E0, 0x00000000FFFFFFE0},
+    {0x00000000000003C0, 0x00000000FFFFFFC0},
+    {0x0000000000000780, 0x00000000FFFFFF80},
+    {0x0000000000000F00, 0x00000000FFFFFF00},
+    {0x0000000000001E00, 0x00000000FFFFFE00},
+    {0x0000000000003C00, 0x00000000FFFFFC00},
+    {0x0000000000007800, 0x00000000FFFFF800},
+    {0x000000000000F000, 0x00000000FFFFF000},
+    {0x000000000001E000, 0x00000000FFFFE000},
+    {0x000000000003C000, 0x00000000FFFFC000},
+    {0x0000000000078000, 0x00000000FFFF8000},
+    {0x00000000000F0000, 0x00000000FFFF0000},
+    {0x00000000001E0000, 0x00000000FFFE0000},
+    {0x00000000003C0000, 0x00000000FFFC0000},
+    {0x0000000000780000, 0x00000000FFF80000},
+    {0x0000000000F00000, 0x00000000FFF00000},
+    {0x0000000001E00000, 0x00000000FFE00000},
+    {0x0000000003C00000, 0x00000000FFC00000},
+    {0x0000000007800000, 0x00000000FF800000},
+    {0x000000000F000000, 0x00000000FF000000},
+    {0x000000001E000000, 0x00000000FE000000},
+    {0x000000003C000000, 0x00000000FC000000},
+    {0x0000000078000000, 0x00000000F8000000},
+    {0x00000000F0000000, 0x00000000F0000000},
+    {0x00000000FFFFFFFF, 0x00000000E0000000}};
+
+static constexpr std::pair<uint64_t, uint64_t> Cheri128AlignmentMasks[] = {
+    {0x0000000000000FFF, 0xFFFFFFFFFFFFFFFF},
+    {0x0000000000001FF8, 0xFFFFFFFFFFFFFFF8},
+    {0x0000000000003FF0, 0xFFFFFFFFFFFFFFF0},
+    {0x0000000000007FE0, 0xFFFFFFFFFFFFFFE0},
+    {0x000000000000FFC0, 0xFFFFFFFFFFFFFFC0},
+    {0x000000000001FF80, 0xFFFFFFFFFFFFFF80},
+    {0x000000000003FF00, 0xFFFFFFFFFFFFFF00},
+    {0x000000000007FE00, 0xFFFFFFFFFFFFFE00},
+    {0x00000000000FFC00, 0xFFFFFFFFFFFFFC00},
+    {0x00000000001FF800, 0xFFFFFFFFFFFFF800},
+    {0x00000000003FF000, 0xFFFFFFFFFFFFF000},
+    {0x00000000007FE000, 0xFFFFFFFFFFFFE000},
+    {0x0000000000FFC000, 0xFFFFFFFFFFFFC000},
+    {0x0000000001FF8000, 0xFFFFFFFFFFFF8000},
+    {0x0000000003FF0000, 0xFFFFFFFFFFFF0000},
+    {0x0000000007FE0000, 0xFFFFFFFFFFFE0000},
+    {0x000000000FFC0000, 0xFFFFFFFFFFFC0000},
+    {0x000000001FF80000, 0xFFFFFFFFFFF80000},
+    {0x000000003FF00000, 0xFFFFFFFFFFF00000},
+    {0x000000007FE00000, 0xFFFFFFFFFFE00000},
+    {0x00000000FFC00000, 0xFFFFFFFFFFC00000},
+    {0x00000001FF800000, 0xFFFFFFFFFF800000},
+    {0x00000003FF000000, 0xFFFFFFFFFF000000},
+    {0x00000007FE000000, 0xFFFFFFFFFE000000},
+    {0x0000000FFC000000, 0xFFFFFFFFFC000000},
+    {0x0000001FF8000000, 0xFFFFFFFFF8000000},
+    {0x0000003FF0000000, 0xFFFFFFFFF0000000},
+    {0x0000007FE0000000, 0xFFFFFFFFE0000000},
+    {0x000000FFC0000000, 0xFFFFFFFFC0000000},
+    {0x000001FF80000000, 0xFFFFFFFF80000000},
+    {0x000003FF00000000, 0xFFFFFFFF00000000},
+    {0x000007FE00000000, 0xFFFFFFFE00000000},
+    {0x00000FFC00000000, 0xFFFFFFFC00000000},
+    {0x00001FF800000000, 0xFFFFFFF800000000},
+    {0x00003FF000000000, 0xFFFFFFF000000000},
+    {0x00007FE000000000, 0xFFFFFFE000000000},
+    {0x0000FFC000000000, 0xFFFFFFC000000000},
+    {0x0001FF8000000000, 0xFFFFFF8000000000},
+    {0x0003FF0000000000, 0xFFFFFF0000000000},
+    {0x0007FE0000000000, 0xFFFFFE0000000000},
+    {0x000FFC0000000000, 0xFFFFFC0000000000},
+    {0x001FF80000000000, 0xFFFFF80000000000},
+    {0x003FF00000000000, 0xFFFFF00000000000},
+    {0x007FE00000000000, 0xFFFFE00000000000},
+    {0x00FFC00000000000, 0xFFFFC00000000000},
+    {0x01FF800000000000, 0xFFFF800000000000},
+    {0x03FF000000000000, 0xFFFF000000000000},
+    {0x07FE000000000000, 0xFFFE000000000000},
+    {0x0FFC000000000000, 0xFFFC000000000000},
+    {0x1FF8000000000000, 0xFFF8000000000000},
+    {0x3FF0000000000000, 0xFFF0000000000000},
+    {0x7FE0000000000000, 0xFFE0000000000000},
+    {0xFFC0000000000000, 0xFFC0000000000000},
+    {0xFFFFFFFFFFFFFFFF, 0xFF80000000000000}};
+
+static constexpr std::pair<uint64_t, uint64_t> Cheriot64AlignmentMasks[] = {
+    {0x00000000000001FF, 0x00000000FFFFFFFF},
+    {0x00000000000003FE, 0x00000000FFFFFFFE},
+    {0x00000000000007FC, 0x00000000FFFFFFFC},
+    {0x0000000000000FF8, 0x00000000FFFFFFF8},
+    {0x0000000000001FF0, 0x00000000FFFFFFF0},
+    {0x0000000000003FE0, 0x00000000FFFFFFE0},
+    {0x0000000000007FC0, 0x00000000FFFFFFC0},
+    {0x000000000000FF80, 0x00000000FFFFFF80},
+    {0x000000000001FF00, 0x00000000FFFFFF00},
+    {0x000000000003FE00, 0x00000000FFFFFE00},
+    {0x000000000007FC00, 0x00000000FFFFFC00},
+    {0x00000000000FF800, 0x00000000FFFFF800},
+    {0x00000000001FF000, 0x00000000FFFFF000},
+    {0x00000000003FE000, 0x00000000FFFFE000},
+    {0x00000000007FC000, 0x00000000FFFFC000},
+    {0x00000000FFFFFFFF, 0x00000000FF000000},
+};
+
+} // namespace
+
+namespace llvm {
+
+const CHERICapabilityFormat CHERICapabilityFormat::Cheri64 =
+    CHERICapabilityFormat(std::numeric_limits<uint32_t>::max(),
+                          Cheri64AlignmentMasks);
+
+const CHERICapabilityFormat CHERICapabilityFormat::Cheri128 =
+    CHERICapabilityFormat(std::numeric_limits<uint64_t>::max(),
+                          Cheri128AlignmentMasks);
+
+const CHERICapabilityFormat CHERICapabilityFormat::Cheriot64 =
+    CHERICapabilityFormat(std::numeric_limits<uint32_t>::max(),
+                          Cheriot64AlignmentMasks);
+
+} // namespace llvm
diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt
index 100cfb567c348..51e5085447a6f 100644
--- a/llvm/lib/Support/CMakeLists.txt
+++ b/llvm/lib/Support/CMakeLists.txt
@@ -165,6 +165,7 @@ add_llvm_component_library(LLVMSupport
   BuryPointer.cpp
   CachePruning.cpp
   Caching.cpp
+  CHERICapabilityFormat.cpp
   circular_raw_ostream.cpp
   Chrono.cpp
   COM.cpp
diff --git a/llvm/unittests/Support/CHERICapabilityFormatTest.cpp b/llvm/unittests/Support/CHERICapabilityFormatTest.cpp
new file mode 100644
index 0000000000000..68b015c21cd28
--- /dev/null
+++ b/llvm/unittests/Support/CHERICapabilityFormatTest.cpp
@@ -0,0 +1,91 @@
+#include "llvm/Support/CHERICapabilityFormat.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+TEST(CHERICapabilityFormat, Cheri64) {
+  const auto &Cheri64 = CHERICapabilityFormat::Cheri64;
+
+  EXPECT_EQ(Cheri64.getAddressMask(), 0xFFFFFFFF);
+
+  // Lengths up to 63 are byte-aligned.
+  for (uint64_t Len = 1; Len <= 63; ++Len) {
+    EXPECT_EQ(Cheri64.getRepresentableLength(Len), Len);
+    EXPECT_EQ(Cheri64.getRequiredAlignment(Len), 1);
+    EXPECT_EQ(Cheri64.getAlignmentMask(Len), 0xFFFFFFFF);
+  }
+
+  // Lengths up to 120 are 8-byte-aligned.
+  for (uint64_t Len = 64; Len <= 120; ++Len) {
+    EXPECT_EQ(Cheri64.getRepresentableLength(Len), (Len + 7) & 0xFFFFFFF8);
+    EXPECT_EQ(Cheri64.getRequiredAlignment(Len), 8);
+    EXPECT_EQ(Cheri64.getAlignmentMask(Len), 0xFFFFFFF8);
+  }
+
+  // Lengths up to 240 are 16-byte-aligned.
+  for (uint64_t Len = 121; Len <= 240; ++Len) {
+    EXPECT_EQ(Cheri64.getRepresentableLength(Len), (Len + 15) & 0xFFFFFFF0);
+    EXPECT_EQ(Cheri64.getRequiredAlignment(Len), 16);
+    EXPECT_EQ(Cheri64.getAlignmentMask(Len), 0xFFFFFFF0);
+  }
+}
+
+TEST(CHERICapabilityFormat, Cheri128) {
+  const auto &Cheri128 = CHERICapabilityFormat::Cheri128;
+
+  EXPECT_EQ(Cheri128.getAddressMask(), 0xFFFFFFFFFFFFFFFF);
+
+  // Lengths up to 4095 are byte-aligned.
+  for (uint64_t Len = 1; Len <= 4095; ++Len) {
+    EXPECT_EQ(Cheri128.getRepresentableLength(Len), Len);
+    EXPECT_EQ(Cheri128.getRequiredAlignment(Len), 1);
+    EXPECT_EQ(Cheri128.getAlignmentMask(Len), 0xFFFFFFFFFFFFFFFF);
+  }
+
+  // Lengths up to 8184 are 8-byte-aligned.
+  for (uint64_t Len = 4096; Len <= 8184; ++Len) {
+    EXPECT_EQ(Cheri128.getRepresentableLength(Len),
+              (Len + 7) & 0xFFFFFFFFFFFFFFF8);
+    EXPECT_EQ(Cheri128.getRequiredAlignment(Len), 8);
+    EXPECT_EQ(Cheri128.getAlignmentMask(Len), 0xFFFFFFFFFFFFFFF8);
+  }
+
+  // Lengths up to 16368 are 16-byte-aligned.
+  for (uint64_t Len = 8185; Len <= 16368; ++Len) {
+    EXPECT_EQ(Cheri128.getRepresentableLength(Len),
+              (Len + 15) & 0xFFFFFFFFFFFFFFF0);
+    EXPECT_EQ(Cheri128.getRequiredAlignment(Len), 16);
+    EXPECT_EQ(Cheri128.getAlignmentMask(Len), 0xFFFFFFFFFFFFFFF0);
+  }
+}
+
+TEST(CHERICapabilityFormat, Cheriot64) {
+  const auto &Cheriot64 = CHERICapabilityFormat::Cheriot64;
+
+  EXPECT_EQ(Cheriot64.getAddressMask(), 0xFFFFFFFF);
+
+  // Lengths up to 511 are byte-aligned.
+  for (uint64_t Len = 1; Len <= 511; ++Len) {
+    EXPECT_EQ(Cheriot64.getRepresentableLength(Len), Len);
+    EXPECT_EQ(Cheriot64.getRequiredAlignment(Len), 1);
+    EXPECT_EQ(Cheriot64.getAlignmentMask(Len), 0xFFFFFFFF);
+  }
+
+  // Lengths up to 1022 are 2-byte-aligned.
+  for (uint64_t Len = 512; Len <= 1022; ++Len) {
+    EXPECT_EQ(Cheriot64.getRepresentableLength(Len), (Len + 1) & 0xFFFFFFFE);
+    EXPECT_EQ(Cheriot64.getRequiredAlignment(Len), 2);
+    EXPECT_EQ(Cheriot64.getAlignmentMask(Len), 0xFFFFFFFE);
+  }
+
+  // Lengths up to 1022 are 4-byte-aligned.
+  for (uint64_t Len = 1023; Len <= 2044; ++Len) {
+    EXPECT_EQ(Cheriot64.getRepresentableLength(Len), (Len + 3) & 0xFFFFFFFC);
+    EXPECT_EQ(Cheriot64.getRequiredAlignment(Len), 4);
+    EXPECT_EQ(Cheriot64.getAlignmentMask(Len), 0xFFFFFFFC);
+  }
+}
+
+} // namespace
diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt
index a8bf96bbe096f..e808e668a87ad 100644
--- a/llvm/unittests/Support/CMakeLists.txt
+++ b/llvm/unittests/Support/CMakeLists.txt
@@ -21,6 +21,7 @@ add_llvm_unittest(SupportTests
   Caching.cpp
   Casting.cpp
   CheckedArithmeticTest.cpp
+  CHERICapabilityFormatTest.cpp
   Chrono.cpp
   CommandLineTest.cpp
   CompressionTest.cpp

>From 427df29cb7b42604f742befcc25e6eba78f62dfb Mon Sep 17 00:00:00 2001
From: Owen Anderson <resistor at mac.com>
Date: Mon, 1 Jun 2026 16:15:31 +0200
Subject: [PATCH 2/2] [wip] Refactor CHERICapabilityFormat to compute the
 relevant alignment requirements rather than using LUTs.

TODO: CHERI64
---
 .../llvm/Support/CHERICapabilityFormat.h      |  48 +++--
 llvm/lib/Support/CHERICapabilityFormat.cpp    | 173 ++++++------------
 2 files changed, 82 insertions(+), 139 deletions(-)

diff --git a/llvm/include/llvm/Support/CHERICapabilityFormat.h b/llvm/include/llvm/Support/CHERICapabilityFormat.h
index f3a0ca2c87bbe..fc462fb2d087a 100644
--- a/llvm/include/llvm/Support/CHERICapabilityFormat.h
+++ b/llvm/include/llvm/Support/CHERICapabilityFormat.h
@@ -12,31 +12,26 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/Support/Alignment.h"
 
-#include <algorithm>
-
 namespace llvm {
 
-class CHERICapabilityFormat {
-  constexpr CHERICapabilityFormat(uint64_t AM,
-                                  ArrayRef<std::pair<uint64_t, uint64_t>> L)
-      : AddressMask(AM), LUT(L) {}
+namespace CHERICapabilityFormat {
+
+class CHERICapabilityFormatImpl {
+protected:
+  constexpr CHERICapabilityFormatImpl(uint64_t AM) : AddressMask(AM) {}
 
-  uint64_t AddressMask;
-  ArrayRef<std::pair<uint64_t, uint64_t>> LUT;
+  const uint64_t AddressMask;
 
 public:
+  virtual ~CHERICapabilityFormatImpl();
+
   /// Returns the mask for the address bits in the capability.
   uint64_t getAddressMask() const { return AddressMask; }
 
   /// Returns the "alignment mask" for an allocation of size \p Length. This
   /// mask is 0 where the capability format alignment requirements for the
   /// address to be 0, and 1 otherwise.
-  uint64_t getAlignmentMask(uint64_t Length) const {
-    auto el = std::find_if(LUT.begin(), LUT.end(),
-                           [=](const auto &p) { return Length <= p.first; });
-    assert(el != LUT.end() && "Could not find alignment mask for length!");
-    return el->second;
-  }
+  virtual uint64_t getAlignmentMask(uint64_t Length) const = 0;
 
   /// Returns the required alignment for an allocation of size \p Length.
   Align getRequiredAlignment(uint64_t Length) const {
@@ -49,12 +44,31 @@ class CHERICapabilityFormat {
     uint64_t Mask = getAlignmentMask(Length);
     return (Length + ~Mask) & Mask;
   }
+};
+
+class CHERIv9CapabilityFormatImpl : public CHERICapabilityFormatImpl {
+public:
+  constexpr CHERIv9CapabilityFormatImpl(uint64_t AM, unsigned MW)
+      : CHERICapabilityFormatImpl(AM), MW(MW) {}
 
-  static const CHERICapabilityFormat Cheriot64;
-  static const CHERICapabilityFormat Cheri64;
-  static const CHERICapabilityFormat Cheri128;
+  const unsigned MW;
+
+  uint64_t getAlignmentMask(uint64_t Length) const override;
+};
+
+class CHERIoTCapabilityFormatImpl : public CHERICapabilityFormatImpl {
+public:
+  constexpr CHERIoTCapabilityFormatImpl()
+      : CHERICapabilityFormatImpl(std::numeric_limits<uint32_t>::max()) {}
+
+  uint64_t getAlignmentMask(uint64_t Length) const override;
 };
 
+extern const CHERIv9CapabilityFormatImpl Cheri64;
+extern const CHERIv9CapabilityFormatImpl Cheri128;
+extern const CHERIoTCapabilityFormatImpl Cheriot64;
+
+} // namespace CHERICapabilityFormat
 } // namespace llvm
 
 #endif
diff --git a/llvm/lib/Support/CHERICapabilityFormat.cpp b/llvm/lib/Support/CHERICapabilityFormat.cpp
index e055b716578e5..9da5068438239 100644
--- a/llvm/lib/Support/CHERICapabilityFormat.cpp
+++ b/llvm/lib/Support/CHERICapabilityFormat.cpp
@@ -7,128 +7,57 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Support/CHERICapabilityFormat.h"
-
-namespace {
-
-constexpr std::pair<uint64_t, uint64_t> Cheri64AlignmentMasks[] = {
-    {0x000000000000003F, 0x00000000FFFFFFFF},
-    {0x0000000000000078, 0x00000000FFFFFFF8},
-    {0x00000000000000F0, 0x00000000FFFFFFF0},
-    {0x00000000000001E0, 0x00000000FFFFFFE0},
-    {0x00000000000003C0, 0x00000000FFFFFFC0},
-    {0x0000000000000780, 0x00000000FFFFFF80},
-    {0x0000000000000F00, 0x00000000FFFFFF00},
-    {0x0000000000001E00, 0x00000000FFFFFE00},
-    {0x0000000000003C00, 0x00000000FFFFFC00},
-    {0x0000000000007800, 0x00000000FFFFF800},
-    {0x000000000000F000, 0x00000000FFFFF000},
-    {0x000000000001E000, 0x00000000FFFFE000},
-    {0x000000000003C000, 0x00000000FFFFC000},
-    {0x0000000000078000, 0x00000000FFFF8000},
-    {0x00000000000F0000, 0x00000000FFFF0000},
-    {0x00000000001E0000, 0x00000000FFFE0000},
-    {0x00000000003C0000, 0x00000000FFFC0000},
-    {0x0000000000780000, 0x00000000FFF80000},
-    {0x0000000000F00000, 0x00000000FFF00000},
-    {0x0000000001E00000, 0x00000000FFE00000},
-    {0x0000000003C00000, 0x00000000FFC00000},
-    {0x0000000007800000, 0x00000000FF800000},
-    {0x000000000F000000, 0x00000000FF000000},
-    {0x000000001E000000, 0x00000000FE000000},
-    {0x000000003C000000, 0x00000000FC000000},
-    {0x0000000078000000, 0x00000000F8000000},
-    {0x00000000F0000000, 0x00000000F0000000},
-    {0x00000000FFFFFFFF, 0x00000000E0000000}};
-
-static constexpr std::pair<uint64_t, uint64_t> Cheri128AlignmentMasks[] = {
-    {0x0000000000000FFF, 0xFFFFFFFFFFFFFFFF},
-    {0x0000000000001FF8, 0xFFFFFFFFFFFFFFF8},
-    {0x0000000000003FF0, 0xFFFFFFFFFFFFFFF0},
-    {0x0000000000007FE0, 0xFFFFFFFFFFFFFFE0},
-    {0x000000000000FFC0, 0xFFFFFFFFFFFFFFC0},
-    {0x000000000001FF80, 0xFFFFFFFFFFFFFF80},
-    {0x000000000003FF00, 0xFFFFFFFFFFFFFF00},
-    {0x000000000007FE00, 0xFFFFFFFFFFFFFE00},
-    {0x00000000000FFC00, 0xFFFFFFFFFFFFFC00},
-    {0x00000000001FF800, 0xFFFFFFFFFFFFF800},
-    {0x00000000003FF000, 0xFFFFFFFFFFFFF000},
-    {0x00000000007FE000, 0xFFFFFFFFFFFFE000},
-    {0x0000000000FFC000, 0xFFFFFFFFFFFFC000},
-    {0x0000000001FF8000, 0xFFFFFFFFFFFF8000},
-    {0x0000000003FF0000, 0xFFFFFFFFFFFF0000},
-    {0x0000000007FE0000, 0xFFFFFFFFFFFE0000},
-    {0x000000000FFC0000, 0xFFFFFFFFFFFC0000},
-    {0x000000001FF80000, 0xFFFFFFFFFFF80000},
-    {0x000000003FF00000, 0xFFFFFFFFFFF00000},
-    {0x000000007FE00000, 0xFFFFFFFFFFE00000},
-    {0x00000000FFC00000, 0xFFFFFFFFFFC00000},
-    {0x00000001FF800000, 0xFFFFFFFFFF800000},
-    {0x00000003FF000000, 0xFFFFFFFFFF000000},
-    {0x00000007FE000000, 0xFFFFFFFFFE000000},
-    {0x0000000FFC000000, 0xFFFFFFFFFC000000},
-    {0x0000001FF8000000, 0xFFFFFFFFF8000000},
-    {0x0000003FF0000000, 0xFFFFFFFFF0000000},
-    {0x0000007FE0000000, 0xFFFFFFFFE0000000},
-    {0x000000FFC0000000, 0xFFFFFFFFC0000000},
-    {0x000001FF80000000, 0xFFFFFFFF80000000},
-    {0x000003FF00000000, 0xFFFFFFFF00000000},
-    {0x000007FE00000000, 0xFFFFFFFE00000000},
-    {0x00000FFC00000000, 0xFFFFFFFC00000000},
-    {0x00001FF800000000, 0xFFFFFFF800000000},
-    {0x00003FF000000000, 0xFFFFFFF000000000},
-    {0x00007FE000000000, 0xFFFFFFE000000000},
-    {0x0000FFC000000000, 0xFFFFFFC000000000},
-    {0x0001FF8000000000, 0xFFFFFF8000000000},
-    {0x0003FF0000000000, 0xFFFFFF0000000000},
-    {0x0007FE0000000000, 0xFFFFFE0000000000},
-    {0x000FFC0000000000, 0xFFFFFC0000000000},
-    {0x001FF80000000000, 0xFFFFF80000000000},
-    {0x003FF00000000000, 0xFFFFF00000000000},
-    {0x007FE00000000000, 0xFFFFE00000000000},
-    {0x00FFC00000000000, 0xFFFFC00000000000},
-    {0x01FF800000000000, 0xFFFF800000000000},
-    {0x03FF000000000000, 0xFFFF000000000000},
-    {0x07FE000000000000, 0xFFFE000000000000},
-    {0x0FFC000000000000, 0xFFFC000000000000},
-    {0x1FF8000000000000, 0xFFF8000000000000},
-    {0x3FF0000000000000, 0xFFF0000000000000},
-    {0x7FE0000000000000, 0xFFE0000000000000},
-    {0xFFC0000000000000, 0xFFC0000000000000},
-    {0xFFFFFFFFFFFFFFFF, 0xFF80000000000000}};
-
-static constexpr std::pair<uint64_t, uint64_t> Cheriot64AlignmentMasks[] = {
-    {0x00000000000001FF, 0x00000000FFFFFFFF},
-    {0x00000000000003FE, 0x00000000FFFFFFFE},
-    {0x00000000000007FC, 0x00000000FFFFFFFC},
-    {0x0000000000000FF8, 0x00000000FFFFFFF8},
-    {0x0000000000001FF0, 0x00000000FFFFFFF0},
-    {0x0000000000003FE0, 0x00000000FFFFFFE0},
-    {0x0000000000007FC0, 0x00000000FFFFFFC0},
-    {0x000000000000FF80, 0x00000000FFFFFF80},
-    {0x000000000001FF00, 0x00000000FFFFFF00},
-    {0x000000000003FE00, 0x00000000FFFFFE00},
-    {0x000000000007FC00, 0x00000000FFFFFC00},
-    {0x00000000000FF800, 0x00000000FFFFF800},
-    {0x00000000001FF000, 0x00000000FFFFF000},
-    {0x00000000003FE000, 0x00000000FFFFE000},
-    {0x00000000007FC000, 0x00000000FFFFC000},
-    {0x00000000FFFFFFFF, 0x00000000FF000000},
-};
-
-} // namespace
+#include "llvm/ADT/bit.h"
 
 namespace llvm {
-
-const CHERICapabilityFormat CHERICapabilityFormat::Cheri64 =
-    CHERICapabilityFormat(std::numeric_limits<uint32_t>::max(),
-                          Cheri64AlignmentMasks);
-
-const CHERICapabilityFormat CHERICapabilityFormat::Cheri128 =
-    CHERICapabilityFormat(std::numeric_limits<uint64_t>::max(),
-                          Cheri128AlignmentMasks);
-
-const CHERICapabilityFormat CHERICapabilityFormat::Cheriot64 =
-    CHERICapabilityFormat(std::numeric_limits<uint32_t>::max(),
-                          Cheriot64AlignmentMasks);
-
+namespace CHERICapabilityFormat {
+CHERICapabilityFormatImpl::~CHERICapabilityFormatImpl() {}
+
+uint64_t CHERIv9CapabilityFormatImpl::getAlignmentMask(uint64_t Length) const {
+  uint64_t MWMask = (1ULL << (MW - 4)) - 1;
+  unsigned BytePrecisionLimit = MW - 2;
+
+  // A zero length could either be interpreted as 2^64 or as 0, neither of
+  // which is a length the compiler should be needing the alignment mask for.
+  assert(Length != 0 && "Alignment mask for ambiguous zero length requested");
+
+  // Because of the IE == 0 case, lengths less than 4KB have no alignment
+  // constraint.
+  if (Length < (1ULL << BytePrecisionLimit))
+    return getAddressMask();
+
+  // E_initial = 52 - CountLeadingZeros(l[64:13]) for MW=14
+  unsigned E_initial = 64 - llvm::countl_zero(Length >> (MW - 1));
+
+  // C = 1 iff any of the Einitial + 3 least significant bits of l are
+  // non-zero and the next MW - 4 least significant bits of l are all 1.
+  unsigned LSBWidth = E_initial + 3;
+  uint64_t LSBMask = (1ULL << LSBWidth) - 1;
+  bool anyLSB = (Length & LSBMask) != 0;
+
+  Length >>= LSBWidth;
+  uint64_t nextAllOnes = (Length & MWMask) == MWMask;
+  unsigned C = anyLSB && nextAllOnes;
+
+  unsigned E = E_initial + C;
+  return getAddressMask() << (E + 3);
+}
+
+uint64_t CHERIoTCapabilityFormatImpl::getAlignmentMask(uint64_t Length) const {
+  // Per section 7.13.4 and table 7.4 in the v1.0 CHERIoT specification.
+  for (unsigned e = 0; e <= 14; ++e) {
+    if (Length <= 511ULL << e)
+      return (0xFFFFFFFFFFFFFFFFULL << e) & getAddressMask();
+  }
+
+  return (0xFFFFFFFFFFFFFFFFULL << 24) & getAddressMask();
+}
+
+const CHERIv9CapabilityFormatImpl Cheri64{std::numeric_limits<uint32_t>::max(),
+                                          15};
+const CHERIv9CapabilityFormatImpl Cheri128{std::numeric_limits<uint64_t>::max(),
+                                           14};
+const CHERIoTCapabilityFormatImpl Cheriot64;
+
+} // namespace CHERICapabilityFormat
 } // namespace llvm



More information about the llvm-commits mailing list