xref: /freebsd/contrib/llvm-project/clang/lib/AST/ByteCode/BitcastBuffer.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //===--------------------- BitcastBuffer.h ----------------------*- C++ -*-===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_BITCAST_BUFFER_H
9*700637cbSDimitry Andric #define LLVM_CLANG_AST_INTERP_BITCAST_BUFFER_H
10*700637cbSDimitry Andric 
11*700637cbSDimitry Andric #include "llvm/ADT/SmallVector.h"
12*700637cbSDimitry Andric #include <cassert>
13*700637cbSDimitry Andric #include <cstddef>
14*700637cbSDimitry Andric #include <memory>
15*700637cbSDimitry Andric 
16*700637cbSDimitry Andric namespace clang {
17*700637cbSDimitry Andric namespace interp {
18*700637cbSDimitry Andric 
19*700637cbSDimitry Andric enum class Endian { Little, Big };
20*700637cbSDimitry Andric 
21*700637cbSDimitry Andric struct Bytes;
22*700637cbSDimitry Andric 
23*700637cbSDimitry Andric /// A quantity in bits.
24*700637cbSDimitry Andric struct Bits {
25*700637cbSDimitry Andric   size_t N = 0;
26*700637cbSDimitry Andric   Bits() = default;
zeroBits27*700637cbSDimitry Andric   static Bits zero() { return Bits(0); }
BitsBits28*700637cbSDimitry Andric   explicit Bits(size_t Quantity) : N(Quantity) {}
getQuantityBits29*700637cbSDimitry Andric   size_t getQuantity() const { return N; }
roundToBytesBits30*700637cbSDimitry Andric   size_t roundToBytes() const { return N / 8; }
getOffsetInByteBits31*700637cbSDimitry Andric   size_t getOffsetInByte() const { return N % 8; }
isFullByteBits32*700637cbSDimitry Andric   bool isFullByte() const { return N % 8 == 0; }
nonZeroBits33*700637cbSDimitry Andric   bool nonZero() const { return N != 0; }
isZeroBits34*700637cbSDimitry Andric   bool isZero() const { return N == 0; }
35*700637cbSDimitry Andric   Bytes toBytes() const;
36*700637cbSDimitry Andric 
37*700637cbSDimitry Andric   Bits operator-(Bits Other) const { return Bits(N - Other.N); }
38*700637cbSDimitry Andric   Bits operator+(Bits Other) const { return Bits(N + Other.N); }
39*700637cbSDimitry Andric   Bits operator+=(size_t O) {
40*700637cbSDimitry Andric     N += O;
41*700637cbSDimitry Andric     return *this;
42*700637cbSDimitry Andric   }
43*700637cbSDimitry Andric   Bits operator+=(Bits O) {
44*700637cbSDimitry Andric     N += O.N;
45*700637cbSDimitry Andric     return *this;
46*700637cbSDimitry Andric   }
47*700637cbSDimitry Andric 
48*700637cbSDimitry Andric   bool operator>=(Bits Other) const { return N >= Other.N; }
49*700637cbSDimitry Andric   bool operator<=(Bits Other) const { return N <= Other.N; }
50*700637cbSDimitry Andric   bool operator==(Bits Other) const { return N == Other.N; }
51*700637cbSDimitry Andric   bool operator!=(Bits Other) const { return N != Other.N; }
52*700637cbSDimitry Andric };
53*700637cbSDimitry Andric 
54*700637cbSDimitry Andric /// A quantity in bytes.
55*700637cbSDimitry Andric struct Bytes {
56*700637cbSDimitry Andric   size_t N;
BytesBytes57*700637cbSDimitry Andric   explicit Bytes(size_t Quantity) : N(Quantity) {}
getQuantityBytes58*700637cbSDimitry Andric   size_t getQuantity() const { return N; }
toBitsBytes59*700637cbSDimitry Andric   Bits toBits() const { return Bits(N * 8); }
60*700637cbSDimitry Andric };
61*700637cbSDimitry Andric 
toBytes()62*700637cbSDimitry Andric inline Bytes Bits::toBytes() const {
63*700637cbSDimitry Andric   assert(isFullByte());
64*700637cbSDimitry Andric   return Bytes(N / 8);
65*700637cbSDimitry Andric }
66*700637cbSDimitry Andric 
67*700637cbSDimitry Andric /// A bit range. Both Start and End are inclusive.
68*700637cbSDimitry Andric struct BitRange {
69*700637cbSDimitry Andric   Bits Start;
70*700637cbSDimitry Andric   Bits End;
71*700637cbSDimitry Andric 
BitRangeBitRange72*700637cbSDimitry Andric   BitRange(Bits Start, Bits End) : Start(Start), End(End) {}
sizeBitRange73*700637cbSDimitry Andric   Bits size() const { return End - Start + Bits(1); }
74*700637cbSDimitry Andric   bool operator<(BitRange Other) const { return Start.N < Other.Start.N; }
75*700637cbSDimitry Andric 
containsBitRange76*700637cbSDimitry Andric   bool contains(Bits B) { return Start <= B && End >= B; }
77*700637cbSDimitry Andric };
78*700637cbSDimitry Andric 
79*700637cbSDimitry Andric /// Track what bits have been initialized to known values and which ones
80*700637cbSDimitry Andric /// have indeterminate value.
81*700637cbSDimitry Andric struct BitcastBuffer {
82*700637cbSDimitry Andric   Bits FinalBitSize;
83*700637cbSDimitry Andric   std::unique_ptr<std::byte[]> Data;
84*700637cbSDimitry Andric   llvm::SmallVector<BitRange> InitializedBits;
85*700637cbSDimitry Andric 
BitcastBufferBitcastBuffer86*700637cbSDimitry Andric   BitcastBuffer(Bits FinalBitSize) : FinalBitSize(FinalBitSize) {
87*700637cbSDimitry Andric     assert(FinalBitSize.isFullByte());
88*700637cbSDimitry Andric     unsigned ByteSize = FinalBitSize.roundToBytes();
89*700637cbSDimitry Andric     Data = std::make_unique<std::byte[]>(ByteSize);
90*700637cbSDimitry Andric   }
91*700637cbSDimitry Andric 
92*700637cbSDimitry Andric   /// Returns the buffer size in bits.
sizeBitcastBuffer93*700637cbSDimitry Andric   Bits size() const { return FinalBitSize; }
byteSizeBitcastBuffer94*700637cbSDimitry Andric   Bytes byteSize() const { return FinalBitSize.toBytes(); }
95*700637cbSDimitry Andric 
96*700637cbSDimitry Andric   /// Returns \c true if all bits in the buffer have been initialized.
97*700637cbSDimitry Andric   bool allInitialized() const;
98*700637cbSDimitry Andric   /// Marks the bits in the given range as initialized.
99*700637cbSDimitry Andric   /// FIXME: Can we do this automatically in pushData()?
100*700637cbSDimitry Andric   void markInitialized(Bits Start, Bits Length);
101*700637cbSDimitry Andric   bool rangeInitialized(Bits Offset, Bits Length) const;
102*700637cbSDimitry Andric 
103*700637cbSDimitry Andric   /// Push \p BitWidth bits at \p BitOffset from \p In into the buffer.
104*700637cbSDimitry Andric   /// \p TargetEndianness is the endianness of the target we're compiling for.
105*700637cbSDimitry Andric   /// \p In must hold at least \p BitWidth many bits.
106*700637cbSDimitry Andric   void pushData(const std::byte *In, Bits BitOffset, Bits BitWidth,
107*700637cbSDimitry Andric                 Endian TargetEndianness);
108*700637cbSDimitry Andric 
109*700637cbSDimitry Andric   /// Copy \p BitWidth bits at offset \p BitOffset from the buffer.
110*700637cbSDimitry Andric   /// \p TargetEndianness is the endianness of the target we're compiling for.
111*700637cbSDimitry Andric   ///
112*700637cbSDimitry Andric   /// The returned output holds exactly (\p FullBitWidth / 8) bytes.
113*700637cbSDimitry Andric   std::unique_ptr<std::byte[]> copyBits(Bits BitOffset, Bits BitWidth,
114*700637cbSDimitry Andric                                         Bits FullBitWidth,
115*700637cbSDimitry Andric                                         Endian TargetEndianness) const;
116*700637cbSDimitry Andric };
117*700637cbSDimitry Andric 
118*700637cbSDimitry Andric } // namespace interp
119*700637cbSDimitry Andric } // namespace clang
120*700637cbSDimitry Andric #endif
121