1//===- CHERICapabilityFormat.cpp ------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/Support/CHERICapabilityFormat.h"
10#include "llvm/ADT/bit.h"
11
12namespace llvm {
13
14template <typename AddressType, unsigned MW, unsigned MAX_E>
15AddressType RVYCapabilityFormat<AddressType, MW, MAX_E>::getAlignmentMaskImpl(
16 uint64_t Length) {
17 static constexpr unsigned int IE_TAKE_BITS = 3;
18
19 if (Length == 0)
20 return RVYCapabilityFormat::AddressMask;
21
22 // Extract bits that overflow the uncompressed mantissa window.
23 uint64_t Slice = static_cast<uint64_t>(Length) >> (MW - 1);
24 unsigned int E = 64 - llvm::countl_zero(Val: Slice);
25 // We use internal exponent if length overflows OR the denormal boundary
26 // bit is set.
27 bool IE = (E != 0) || ((static_cast<uint64_t>(Length) >> (MW - 2)) & 1);
28 // Include bits used by the internal exponent for the shift value.
29 unsigned int Eprime = IE ? (E + IE_TAKE_BITS) : 0;
30
31 assert(E <= MAX_E && "Raw exponent exceeds architecture maximum");
32 assert(Eprime <= sizeof(AddressType) * 8 &&
33 "Shift amount exceeds integer width");
34
35 // Left-shift ~0 to mask out the lost precision bits
36 return RVYCapabilityFormat::AddressMask << Eprime;
37}
38
39template struct CHERICapabilityFormatBase<RVYCapabilityFormat<uint32_t, 10, 24>,
40 uint32_t>;
41template struct CHERICapabilityFormatBase<RVYCapabilityFormat<uint64_t, 14, 52>,
42 uint64_t>;
43template struct RVYCapabilityFormat<uint32_t, 10, 24>;
44template struct RVYCapabilityFormat<uint64_t, 14, 52>;
45
46uint32_t CHERIoTCapabilityFormat::getAlignmentMaskImpl(uint32_t Length) {
47 // Per section 7.13.4 and table 7.4 in the v1.0 CHERIoT specification.
48 constexpr uint32_t NINE_SET_BITS = 511;
49 uint32_t E;
50 if (Length > NINE_SET_BITS << 14)
51 E = 24;
52 else {
53 E = Length > NINE_SET_BITS ? 32 - llvm::countl_zero(Val: Length) - 9 : 0;
54 if (Length > NINE_SET_BITS << E)
55 ++E;
56 assert(E <= 14 && "CHERIoT capabilities cannot encode E between 14 and 24");
57 }
58 return CHERIoTCapabilityFormat::AddressMask << E;
59}
60
61template struct CHERICapabilityFormatBase<CHERIoTCapabilityFormat, uint32_t>;
62
63} // namespace llvm
64