Files
llvm-tms34010/llvm/lib/Support/CHERICapabilityFormat.cpp
Jessica Clarke 3ff82c7e55 [Support][CHERI] Refactor CHERICapabilityFormatBase to embrace CRTP (#205623)
Currently CHERICapabilityFormatBase does not provide a definition for
getAlignmentMask, but does provide a declaration, which leads to
warnings when building with MSVC. We want to have an abstract base here
without any dynamic dispatch, which is what CRTP is for, so use it for
getAlignmentMask such that the base can provide a definition that uses
each derived type's implementation, just as the two base wrappers were
already doing when calling getAlignmentMask. Whilst doing this we might
as well move the wrappers to the header so they can be inlined (and now
that getAlignmentMask is defined we can use it in the helpers rather
than needing each of them to explicitly use the derived type).

Fixes: 7dc09d0d3c ("[CHERI] Add a Support utility for determining
alignment requirements of CHERI capabilities. (#197402)")
2026-06-25 13:09:06 +01:00

64 lines
2.4 KiB
C++

//===- 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"
#include "llvm/ADT/bit.h"
namespace llvm {
template <typename AddressType, unsigned MW, unsigned MAX_E>
AddressType RVYCapabilityFormat<AddressType, MW, MAX_E>::getAlignmentMaskImpl(
uint64_t Length) {
static constexpr unsigned int IE_TAKE_BITS = 3;
if (Length == 0)
return RVYCapabilityFormat::AddressMask;
// Extract bits that overflow the uncompressed mantissa window.
uint64_t Slice = static_cast<uint64_t>(Length) >> (MW - 1);
unsigned int E = 64 - llvm::countl_zero(Slice);
// We use internal exponent if length overflows OR the denormal boundary
// bit is set.
bool IE = (E != 0) || ((static_cast<uint64_t>(Length) >> (MW - 2)) & 1);
// Include bits used by the internal exponent for the shift value.
unsigned int Eprime = IE ? (E + IE_TAKE_BITS) : 0;
assert(E <= MAX_E && "Raw exponent exceeds architecture maximum");
assert(Eprime <= sizeof(AddressType) * 8 &&
"Shift amount exceeds integer width");
// Left-shift ~0 to mask out the lost precision bits
return RVYCapabilityFormat::AddressMask << Eprime;
}
template struct CHERICapabilityFormatBase<RVYCapabilityFormat<uint32_t, 10, 24>,
uint32_t>;
template struct CHERICapabilityFormatBase<RVYCapabilityFormat<uint64_t, 14, 52>,
uint64_t>;
template struct RVYCapabilityFormat<uint32_t, 10, 24>;
template struct RVYCapabilityFormat<uint64_t, 14, 52>;
uint32_t CHERIoTCapabilityFormat::getAlignmentMaskImpl(uint32_t Length) {
// Per section 7.13.4 and table 7.4 in the v1.0 CHERIoT specification.
constexpr uint32_t NINE_SET_BITS = 511;
uint32_t E;
if (Length > NINE_SET_BITS << 14)
E = 24;
else {
E = Length > NINE_SET_BITS ? 32 - llvm::countl_zero(Length) - 9 : 0;
if (Length > NINE_SET_BITS << E)
++E;
assert(E <= 14 && "CHERIoT capabilities cannot encode E between 14 and 24");
}
return CHERIoTCapabilityFormat::AddressMask << E;
}
template struct CHERICapabilityFormatBase<CHERIoTCapabilityFormat, uint32_t>;
} // namespace llvm