xref: /llvm-project/clang/lib/AST/ByteCode/BitcastBuffer.h (revision 8713914d76cb9d6b54278dd75fecb68bb93f6ea5)
112ca72baSTimm Bäder //===--------------------- BitcastBuffer.h ----------------------*- C++ -*-===//
212ca72baSTimm Bäder //
312ca72baSTimm Bäder // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
412ca72baSTimm Bäder // See https://llvm.org/LICENSE.txt for license information.
512ca72baSTimm Bäder // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
612ca72baSTimm Bäder //
712ca72baSTimm Bäder //===----------------------------------------------------------------------===//
812ca72baSTimm Bäder #ifndef LLVM_CLANG_AST_INTERP_BITCAST_BUFFER_H
912ca72baSTimm Bäder #define LLVM_CLANG_AST_INTERP_BITCAST_BUFFER_H
1012ca72baSTimm Bäder 
112f9cd43aSTimm Baeder #include "llvm/ADT/SmallVector.h"
1212ca72baSTimm Bäder #include <cassert>
1312ca72baSTimm Bäder #include <cstddef>
1412ca72baSTimm Bäder #include <memory>
1512ca72baSTimm Bäder 
1612ca72baSTimm Bäder namespace clang {
1712ca72baSTimm Bäder namespace interp {
1812ca72baSTimm Bäder 
1912ca72baSTimm Bäder enum class Endian { Little, Big };
2012ca72baSTimm Bäder 
21*8713914dSTimm Baeder struct Bytes;
22*8713914dSTimm Baeder 
2312ca72baSTimm Bäder /// A quantity in bits.
2412ca72baSTimm Bäder struct Bits {
2512ca72baSTimm Bäder   size_t N = 0;
2612ca72baSTimm Bäder   Bits() = default;
2712ca72baSTimm Bäder   static Bits zero() { return Bits(0); }
2812ca72baSTimm Bäder   explicit Bits(size_t Quantity) : N(Quantity) {}
2912ca72baSTimm Bäder   size_t getQuantity() const { return N; }
3012ca72baSTimm Bäder   size_t roundToBytes() const { return N / 8; }
3112ca72baSTimm Bäder   size_t getOffsetInByte() const { return N % 8; }
3212ca72baSTimm Bäder   bool isFullByte() const { return N % 8 == 0; }
3312ca72baSTimm Bäder   bool nonZero() const { return N != 0; }
347aec6dc4STimm Baeder   bool isZero() const { return N == 0; }
35*8713914dSTimm Baeder   Bytes toBytes() const;
3612ca72baSTimm Bäder 
372f9cd43aSTimm Baeder   Bits operator-(Bits Other) const { return Bits(N - Other.N); }
382f9cd43aSTimm Baeder   Bits operator+(Bits Other) const { return Bits(N + Other.N); }
3912ca72baSTimm Bäder   Bits operator+=(size_t O) {
4012ca72baSTimm Bäder     N += O;
4112ca72baSTimm Bäder     return *this;
4212ca72baSTimm Bäder   }
432f9cd43aSTimm Baeder   Bits operator+=(Bits O) {
442f9cd43aSTimm Baeder     N += O.N;
452f9cd43aSTimm Baeder     return *this;
462f9cd43aSTimm Baeder   }
4712ca72baSTimm Bäder 
482f9cd43aSTimm Baeder   bool operator>=(Bits Other) const { return N >= Other.N; }
492f9cd43aSTimm Baeder   bool operator<=(Bits Other) const { return N <= Other.N; }
502f9cd43aSTimm Baeder   bool operator==(Bits Other) const { return N == Other.N; }
511fbbf4c4STimm Baeder   bool operator!=(Bits Other) const { return N != Other.N; }
5212ca72baSTimm Bäder };
5312ca72baSTimm Bäder 
5412ca72baSTimm Bäder /// A quantity in bytes.
5512ca72baSTimm Bäder struct Bytes {
5612ca72baSTimm Bäder   size_t N;
5712ca72baSTimm Bäder   explicit Bytes(size_t Quantity) : N(Quantity) {}
5812ca72baSTimm Bäder   size_t getQuantity() const { return N; }
5912ca72baSTimm Bäder   Bits toBits() const { return Bits(N * 8); }
6012ca72baSTimm Bäder };
6112ca72baSTimm Bäder 
62*8713914dSTimm Baeder inline Bytes Bits::toBytes() const {
63*8713914dSTimm Baeder   assert(isFullByte());
64*8713914dSTimm Baeder   return Bytes(N / 8);
65*8713914dSTimm Baeder }
66*8713914dSTimm Baeder 
67b4150ed1STimm Baeder /// A bit range. Both Start and End are inclusive.
682f9cd43aSTimm Baeder struct BitRange {
692f9cd43aSTimm Baeder   Bits Start;
702f9cd43aSTimm Baeder   Bits End;
712f9cd43aSTimm Baeder 
722f9cd43aSTimm Baeder   BitRange(Bits Start, Bits End) : Start(Start), End(End) {}
732f9cd43aSTimm Baeder   Bits size() const { return End - Start + Bits(1); }
742f9cd43aSTimm Baeder   bool operator<(BitRange Other) const { return Start.N < Other.Start.N; }
75b4150ed1STimm Baeder 
76b4150ed1STimm Baeder   bool contains(Bits B) { return Start <= B && End >= B; }
772f9cd43aSTimm Baeder };
782f9cd43aSTimm Baeder 
7912ca72baSTimm Bäder /// Track what bits have been initialized to known values and which ones
8012ca72baSTimm Bäder /// have indeterminate value.
8112ca72baSTimm Bäder struct BitcastBuffer {
8212ca72baSTimm Bäder   Bits FinalBitSize;
8312ca72baSTimm Bäder   std::unique_ptr<std::byte[]> Data;
842f9cd43aSTimm Baeder   llvm::SmallVector<BitRange> InitializedBits;
8512ca72baSTimm Bäder 
8612ca72baSTimm Bäder   BitcastBuffer(Bits FinalBitSize) : FinalBitSize(FinalBitSize) {
8712ca72baSTimm Bäder     assert(FinalBitSize.isFullByte());
8812ca72baSTimm Bäder     unsigned ByteSize = FinalBitSize.roundToBytes();
8912ca72baSTimm Bäder     Data = std::make_unique<std::byte[]>(ByteSize);
9012ca72baSTimm Bäder   }
9112ca72baSTimm Bäder 
9212ca72baSTimm Bäder   /// Returns the buffer size in bits.
9312ca72baSTimm Bäder   Bits size() const { return FinalBitSize; }
94*8713914dSTimm Baeder   Bytes byteSize() const { return FinalBitSize.toBytes(); }
9512ca72baSTimm Bäder 
9612ca72baSTimm Bäder   /// Returns \c true if all bits in the buffer have been initialized.
972f9cd43aSTimm Baeder   bool allInitialized() const;
982f9cd43aSTimm Baeder   /// Marks the bits in the given range as initialized.
992f9cd43aSTimm Baeder   /// FIXME: Can we do this automatically in pushData()?
1002f9cd43aSTimm Baeder   void markInitialized(Bits Start, Bits Length);
101b4150ed1STimm Baeder   bool rangeInitialized(Bits Offset, Bits Length) const;
10212ca72baSTimm Bäder 
10312ca72baSTimm Bäder   /// Push \p BitWidth bits at \p BitOffset from \p In into the buffer.
10412ca72baSTimm Bäder   /// \p TargetEndianness is the endianness of the target we're compiling for.
10512ca72baSTimm Bäder   /// \p In must hold at least \p BitWidth many bits.
10612ca72baSTimm Bäder   void pushData(const std::byte *In, Bits BitOffset, Bits BitWidth,
10712ca72baSTimm Bäder                 Endian TargetEndianness);
10812ca72baSTimm Bäder 
10912ca72baSTimm Bäder   /// Copy \p BitWidth bits at offset \p BitOffset from the buffer.
11012ca72baSTimm Bäder   /// \p TargetEndianness is the endianness of the target we're compiling for.
11112ca72baSTimm Bäder   ///
11212ca72baSTimm Bäder   /// The returned output holds exactly (\p FullBitWidth / 8) bytes.
11312ca72baSTimm Bäder   std::unique_ptr<std::byte[]> copyBits(Bits BitOffset, Bits BitWidth,
11412ca72baSTimm Bäder                                         Bits FullBitWidth,
11512ca72baSTimm Bäder                                         Endian TargetEndianness) const;
11612ca72baSTimm Bäder };
11712ca72baSTimm Bäder 
11812ca72baSTimm Bäder } // namespace interp
11912ca72baSTimm Bäder } // namespace clang
12012ca72baSTimm Bäder #endif
121