xref: /llvm-project/clang/lib/AST/ByteCode/BitcastBuffer.h (revision 8713914d76cb9d6b54278dd75fecb68bb93f6ea5)
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