1 //===--------------------- BitcastBuffer.h ----------------------*- C++ -*-===// 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 #ifndef LLVM_CLANG_AST_INTERP_BITCAST_BUFFER_H 9 #define LLVM_CLANG_AST_INTERP_BITCAST_BUFFER_H 10 11 #include "llvm/ADT/SmallVector.h" 12 #include <cassert> 13 #include <cstddef> 14 #include <memory> 15 16 namespace clang { 17 namespace interp { 18 19 enum class Endian { Little, Big }; 20 21 struct Bytes; 22 23 /// A quantity in bits. 24 struct Bits { 25 size_t N = 0; 26 Bits() = default; 27 static Bits zero() { return Bits(0); } 28 explicit Bits(size_t Quantity) : N(Quantity) {} 29 size_t getQuantity() const { return N; } 30 size_t roundToBytes() const { return N / 8; } 31 size_t getOffsetInByte() const { return N % 8; } 32 bool isFullByte() const { return N % 8 == 0; } 33 bool nonZero() const { return N != 0; } 34 bool isZero() const { return N == 0; } 35 Bytes toBytes() const; 36 37 Bits operator-(Bits Other) const { return Bits(N - Other.N); } 38 Bits operator+(Bits Other) const { return Bits(N + Other.N); } 39 Bits operator+=(size_t O) { 40 N += O; 41 return *this; 42 } 43 Bits operator+=(Bits O) { 44 N += O.N; 45 return *this; 46 } 47 48 bool operator>=(Bits Other) const { return N >= Other.N; } 49 bool operator<=(Bits Other) const { return N <= Other.N; } 50 bool operator==(Bits Other) const { return N == Other.N; } 51 bool operator!=(Bits Other) const { return N != Other.N; } 52 }; 53 54 /// A quantity in bytes. 55 struct Bytes { 56 size_t N; 57 explicit Bytes(size_t Quantity) : N(Quantity) {} 58 size_t getQuantity() const { return N; } 59 Bits toBits() const { return Bits(N * 8); } 60 }; 61 62 inline Bytes Bits::toBytes() const { 63 assert(isFullByte()); 64 return Bytes(N / 8); 65 } 66 67 /// A bit range. Both Start and End are inclusive. 68 struct BitRange { 69 Bits Start; 70 Bits End; 71 72 BitRange(Bits Start, Bits End) : Start(Start), End(End) {} 73 Bits size() const { return End - Start + Bits(1); } 74 bool operator<(BitRange Other) const { return Start.N < Other.Start.N; } 75 76 bool contains(Bits B) { return Start <= B && End >= B; } 77 }; 78 79 /// Track what bits have been initialized to known values and which ones 80 /// have indeterminate value. 81 struct BitcastBuffer { 82 Bits FinalBitSize; 83 std::unique_ptr<std::byte[]> Data; 84 llvm::SmallVector<BitRange> InitializedBits; 85 86 BitcastBuffer(Bits FinalBitSize) : FinalBitSize(FinalBitSize) { 87 assert(FinalBitSize.isFullByte()); 88 unsigned ByteSize = FinalBitSize.roundToBytes(); 89 Data = std::make_unique<std::byte[]>(ByteSize); 90 } 91 92 /// Returns the buffer size in bits. 93 Bits size() const { return FinalBitSize; } 94 Bytes byteSize() const { return FinalBitSize.toBytes(); } 95 96 /// Returns \c true if all bits in the buffer have been initialized. 97 bool allInitialized() const; 98 /// Marks the bits in the given range as initialized. 99 /// FIXME: Can we do this automatically in pushData()? 100 void markInitialized(Bits Start, Bits Length); 101 bool rangeInitialized(Bits Offset, Bits Length) const; 102 103 /// Push \p BitWidth bits at \p BitOffset from \p In into the buffer. 104 /// \p TargetEndianness is the endianness of the target we're compiling for. 105 /// \p In must hold at least \p BitWidth many bits. 106 void pushData(const std::byte *In, Bits BitOffset, Bits BitWidth, 107 Endian TargetEndianness); 108 109 /// Copy \p BitWidth bits at offset \p BitOffset from the buffer. 110 /// \p TargetEndianness is the endianness of the target we're compiling for. 111 /// 112 /// The returned output holds exactly (\p FullBitWidth / 8) bytes. 113 std::unique_ptr<std::byte[]> copyBits(Bits BitOffset, Bits BitWidth, 114 Bits FullBitWidth, 115 Endian TargetEndianness) const; 116 }; 117 118 } // namespace interp 119 } // namespace clang 120 #endif 121