blob: 322870affc2f104e8d213934dff1c1a3304cfdd1 [file] [edit]
//===- 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