//===--------------------- BitcastBuffer.h ----------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_INTERP_BITCAST_BUFFER_H #define LLVM_CLANG_AST_INTERP_BITCAST_BUFFER_H #include "llvm/ADT/SmallVector.h" #include #include #include namespace clang { namespace interp { enum class Endian { Little, Big }; struct Bytes; /// A quantity in bits. struct Bits { size_t N = 0; Bits() = default; static Bits zero() { return Bits(0); } explicit Bits(size_t Quantity) : N(Quantity) {} size_t getQuantity() const { return N; } size_t roundToBytes() const { return N / 8; } size_t getOffsetInByte() const { return N % 8; } bool isFullByte() const { return N % 8 == 0; } bool nonZero() const { return N != 0; } bool isZero() const { return N == 0; } Bytes toBytes() const; Bits operator-(Bits Other) const { return Bits(N - Other.N); } Bits operator+(Bits Other) const { return Bits(N + Other.N); } Bits operator+=(size_t O) { N += O; return *this; } Bits operator+=(Bits O) { N += O.N; return *this; } bool operator>=(Bits Other) const { return N >= Other.N; } bool operator<=(Bits Other) const { return N <= Other.N; } bool operator==(Bits Other) const { return N == Other.N; } bool operator!=(Bits Other) const { return N != Other.N; } }; /// A quantity in bytes. struct Bytes { size_t N; explicit Bytes(size_t Quantity) : N(Quantity) {} size_t getQuantity() const { return N; } Bits toBits() const { return Bits(N * 8); } }; inline Bytes Bits::toBytes() const { assert(isFullByte()); return Bytes(N / 8); } /// A bit range. Both Start and End are inclusive. struct BitRange { Bits Start; Bits End; BitRange(Bits Start, Bits End) : Start(Start), End(End) {} Bits size() const { return End - Start + Bits(1); } bool operator<(BitRange Other) const { return Start.N < Other.Start.N; } bool contains(Bits B) { return Start <= B && End >= B; } }; /// Track what bits have been initialized to known values and which ones /// have indeterminate value. struct BitcastBuffer { Bits FinalBitSize; std::unique_ptr Data; llvm::SmallVector InitializedBits; BitcastBuffer(Bits FinalBitSize) : FinalBitSize(FinalBitSize) { assert(FinalBitSize.isFullByte()); unsigned ByteSize = FinalBitSize.roundToBytes(); Data = std::make_unique(ByteSize); } /// Returns the buffer size in bits. Bits size() const { return FinalBitSize; } Bytes byteSize() const { return FinalBitSize.toBytes(); } /// Returns \c true if all bits in the buffer have been initialized. bool allInitialized() const; /// Marks the bits in the given range as initialized. /// FIXME: Can we do this automatically in pushData()? void markInitialized(Bits Start, Bits Length); bool rangeInitialized(Bits Offset, Bits Length) const; /// Push \p BitWidth bits at \p BitOffset from \p In into the buffer. /// \p TargetEndianness is the endianness of the target we're compiling for. /// \p In must hold at least \p BitWidth many bits. void pushData(const std::byte *In, Bits BitOffset, Bits BitWidth, Endian TargetEndianness); /// Copy \p BitWidth bits at offset \p BitOffset from the buffer. /// \p TargetEndianness is the endianness of the target we're compiling for. /// /// The returned output holds exactly (\p FullBitWidth / 8) bytes. std::unique_ptr copyBits(Bits BitOffset, Bits BitWidth, Bits FullBitWidth, Endian TargetEndianness) const; }; } // namespace interp } // namespace clang #endif