| 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 | |
| 12 | namespace llvm { |
| 13 | |
| 14 | template <typename AddressType, unsigned MW, unsigned MAX_E> |
| 15 | AddressType 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 | |
| 39 | template struct CHERICapabilityFormatBase<RVYCapabilityFormat<uint32_t, 10, 24>, |
| 40 | uint32_t>; |
| 41 | template struct CHERICapabilityFormatBase<RVYCapabilityFormat<uint64_t, 14, 52>, |
| 42 | uint64_t>; |
| 43 | template struct RVYCapabilityFormat<uint32_t, 10, 24>; |
| 44 | template struct RVYCapabilityFormat<uint64_t, 14, 52>; |
| 45 | |
| 46 | uint32_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 | |
| 61 | template struct CHERICapabilityFormatBase<CHERIoTCapabilityFormat, uint32_t>; |
| 62 | |
| 63 | } // namespace llvm |
| 64 | |