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