aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/AST/ByteCode/BitcastBuffer.h
blob: d1d6ee39ad17bc5251721ac0dfb3aa4ab01d40f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//===--------------------- 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 <cassert>
#include <cstddef>
#include <memory>

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<std::byte[]> Data;
  llvm::SmallVector<BitRange> InitializedBits;

  BitcastBuffer(Bits FinalBitSize) : FinalBitSize(FinalBitSize) {
    assert(FinalBitSize.isFullByte());
    unsigned ByteSize = FinalBitSize.roundToBytes();
    Data = std::make_unique<std::byte[]>(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<std::byte[]> copyBits(Bits BitOffset, Bits BitWidth,
                                        Bits FullBitWidth,
                                        Endian TargetEndianness) const;
};

} // namespace interp
} // namespace clang
#endif