CIRCT 22.0.0git
Loading...
Searching...
No Matches
Values.h
Go to the documentation of this file.
1//===- values.h - ESI value system -------------------------------* C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// ESI arbitrary width bitvector and integer types.
10// These types are not meant to be highly optimized. Rather, its a simple
11// implementation to support arbitrary bit widths for ESI runtime values.
12//
13//===----------------------------------------------------------------------===//
14// DO NOT EDIT!
15// This file is distributed as part of an ESI package. The source for this file
16// should always be modified within CIRCT.
17//
18//===----------------------------------------------------------------------===//
19
20// NOLINTNEXTLINE(llvm-header-guard)
21#ifndef ESI_VALUES_H
22#define ESI_VALUES_H
23
24#include <cstdint>
25#include <format>
26#include <memory> // (may be removable later)
27#include <optional>
28#include <ostream>
29#include <span>
30#include <stdexcept>
31#include <string>
32#include <vector>
33
34namespace esi {
35
36class MutableBitVector;
37
38/// A lightweight, non-owning bit vector view backed by a byte array span.
39/// BitVector is immutable wrt. modifying the underlying bits, and provides
40/// read-only access to bits. It supports bit-level access and returns new views
41/// for operations.
42class BitVector {
43public:
44 using byte = uint8_t;
45
46 /// Construct from an existing span. Width defaults to the number of bits in
47 /// the span (size * 8). The BitVector does not take ownership.
48 BitVector(std::span<const byte> bytes,
49 std::optional<size_t> width = std::nullopt, uint8_t bitIndex = 0);
50 BitVector() = default;
51 BitVector(const BitVector &other);
52 BitVector &operator=(const BitVector &other);
53
54 size_t width() const { return bitWidth; }
55 size_t size() const { return width(); }
56
57 /// Return the i-th bit (0 = LSB) as boolean.
58 bool getBit(size_t i) const;
59
60 /// Return a handle to the underlying span. Throws if the current bit index
61 /// is not 0 (since a non-zero bit offset breaks raw byte alignment).
62 std::span<const byte> getSpan() const {
63 if (bitIndex != 0)
64 throw std::runtime_error("Cannot get data span with non-zero bit index");
65 return data;
66 }
67
68 /// Logical right shift that drops the least-significant n bits by advancing
69 /// the byte/bit index and reducing width. Returns a new immutable
70 /// view. Does not modify the underlying storage contents.
71 BitVector operator>>(size_t n) const;
72 BitVector &operator>>=(size_t n);
73
74 /// Create a new immutable view of a contiguous bit slice [offset,
75 /// offset+sliceWidth). The returned BitVector is a view (not an owning copy)
76 /// into the same underlying span. Throws if the requested slice exceeds the
77 /// current width.
78 BitVector slice(size_t offset, size_t sliceWidth) const;
79
80 /// Return a view of the N least-significant bits.
81 BitVector lsb(size_t n) const { return slice(0, n); }
82
83 /// Return a view of the N most-significant bits.
84 BitVector msb(size_t n) const {
85 if (n > bitWidth)
86 throw std::invalid_argument("msb width exceeds bit width");
87 return slice(bitWidth - n, n);
88 }
89
90 std::string toString(unsigned base = 16) const;
91
92 bool operator==(const BitVector &rhs) const;
93 bool operator!=(const BitVector &rhs) const { return !(*this == rhs); }
94
95 /// Bitwise AND: creates a new MutableBitVector with the result.
96 friend MutableBitVector operator&(const BitVector &a, const BitVector &b);
97
98 /// Bitwise OR: creates a new MutableBitVector with the result.
99 friend MutableBitVector operator|(const BitVector &a, const BitVector &b);
100
101 /// Bitwise XOR: creates a new MutableBitVector with the result.
102 friend MutableBitVector operator^(const BitVector &a, const BitVector &b);
103
104 /// Forward iterator for iterating over bits from LSB (index 0) to MSB.
106 public:
107 using difference_type = std::ptrdiff_t;
108 using value_type = bool;
109 using pointer = const bool *;
110 using reference = bool;
111 using iterator_category = std::forward_iterator_tag;
112
113 /// Default constructor.
114 bit_iterator() = default;
115
116 /// Construct an iterator at the given bit position.
117 bit_iterator(const BitVector *bv, size_t pos = 0)
118 : bitVector(bv), position(pos) {}
119
120 /// Dereference: returns the bit value at the current position.
121 bool operator*() const {
122 if (bitVector == nullptr || position >= bitVector->bitWidth)
123 throw std::out_of_range("bit_iterator dereference out of range");
124 return bitVector->getBit(position);
125 }
126
127 /// Pre-increment: move to next bit.
129 ++position;
130 return *this;
131 }
132
133 /// Post-increment: move to next bit.
135 bit_iterator tmp = *this;
136 ++position;
137 return tmp;
138 }
139
140 /// Equality comparison.
141 bool operator==(const bit_iterator &other) const {
142 return bitVector == other.bitVector && position == other.position;
143 }
144
145 /// Inequality comparison.
146 bool operator!=(const bit_iterator &other) const {
147 return !(*this == other);
148 }
149
150 /// Less-than comparison (for ranges support).
151 bool operator<(const bit_iterator &other) const {
152 return bitVector == other.bitVector && position < other.position;
153 }
154
155 /// Sentinel-compatible equality (for ranges support).
156 bool operator==(std::default_sentinel_t) const {
157 return bitVector == nullptr || position >= bitVector->bitWidth;
158 }
159
160 /// Sentinel-compatible inequality.
161 bool operator!=(std::default_sentinel_t sent) const {
162 return !(*this == sent);
163 }
164
165 private:
166 const BitVector *bitVector = nullptr;
167 size_t position = 0;
168 };
169
170 /// Return an iterator to the first bit (LSB).
171 bit_iterator begin() const { return bit_iterator(this, 0); }
172
173 /// Return an iterator past the last bit.
174 bit_iterator end() const { return bit_iterator(this, bitWidth); }
175
176protected:
177 // Underlying storage view. const, to allow for non-owning immutable views.
178 std::span<const byte> data{};
179 size_t bitWidth = 0; // Number of valid bits.
180 uint8_t bitIndex = 0; // Starting bit offset in first byte.
181};
182
183/// A mutable bit vector that owns its underlying storage.
184/// It supports in-place modifications and mutable operations.
186public:
187 /// Owning, zero-initialized constructor of a given width.
188 explicit MutableBitVector(size_t width);
189
190 /// Owning constructor from an rvalue vector (must move in).
191 MutableBitVector(std::vector<byte> &&bytes,
192 std::optional<size_t> width = std::nullopt);
193
194 MutableBitVector() = default;
195
196 // Copy constructor: duplicate storage.
198
199 // Copy constructor from immutable BitVector: creates owning copy.
200 MutableBitVector(const BitVector &other);
201
202 // Move constructor: transfer ownership.
203 MutableBitVector(MutableBitVector &&other) noexcept;
204
205 // Move constructor from immutable BitVector: creates owning copy.
207
209
211
212 /// Set the i-th bit.
213 void setBit(size_t i, bool v);
214
215 /// Return a handle to the underlying span (always aligned since bitIndex=0).
216 std::span<const byte> getSpan() const { return data; }
217
218 /// Return and transfer ownership of the underlying storage.
219 std::vector<uint8_t> takeStorage() { return std::move(owner); }
220
221 /// In-place logical right shift that drops the least-significant n bits.
222 /// Reduces width and updates internal state. Does not modify underlying
223 /// storage.
224 MutableBitVector &operator>>=(size_t n);
225
226 /// In-place logical left shift shifts in n zero bits at LSB, shifting
227 /// existing bits upward.
228 MutableBitVector &operator<<=(size_t n);
229
230 /// In-place concatenate: appends bits from other to this.
232
237 MutableBitVector operator|(const MutableBitVector &other) const;
238 MutableBitVector operator&(const MutableBitVector &other) const;
239 MutableBitVector operator^(const MutableBitVector &other) const;
240
241private:
242 // Storage owned by this MutableBitVector.
243 std::vector<byte> owner;
244};
245
246std::ostream &operator<<(std::ostream &os, const BitVector &bv);
247
248// Arbitrary width signed integer type built on MutableBitVector.
249class Int : public MutableBitVector {
250public:
252 Int() = default;
253 Int(int64_t v, unsigned width = 64);
254 operator int64_t() const { return toI64(); }
255 operator int32_t() const { return toInt<int32_t>(); }
256 operator int16_t() const { return toInt<int16_t>(); }
257 operator int8_t() const { return toInt<int8_t>(); }
258
259private:
260 template <typename T>
261 T toInt() const {
262 static_assert(std::is_integral<T>::value && std::is_signed<T>::value,
263 "T must be a signed integral type");
264 int64_t v = toI64();
265 fits(v, sizeof(T) * 8);
266 return static_cast<T>(v);
267 }
268
269 // Convert the bitvector to a signed intN_t, throwing if the value doesn't
270 // fit.
271 int64_t toI64() const;
272
273 // Check if the given value fits in the specified bit width.
274 static void fits(int64_t v, unsigned n);
275};
276
277// Arbitrary width unsigned integer type built on MutableBitVector.
278class UInt : public MutableBitVector {
279public:
281 UInt() = default;
282 UInt(uint64_t v, unsigned width = 64);
283 operator uint64_t() const { return toUI64(); }
284 operator uint32_t() const { return toUInt<uint32_t>(); }
285 operator uint16_t() const { return toUInt<uint16_t>(); }
286 operator uint8_t() const { return toUInt<uint8_t>(); }
287
288private:
289 uint64_t toUI64() const;
290
291 static void fits(uint64_t v, unsigned n);
292
293 template <typename T>
294 T toUInt() const {
295 static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value,
296 "T must be an unsigned integral type");
297 uint64_t v = toUI64();
298 fits(v, sizeof(T) * 8);
299 return static_cast<T>(v);
300 }
301};
302
303} // namespace esi
304
305// Enable BitVector and MutableBitVector to work with std::ranges algorithms
306template <>
307inline constexpr bool std::ranges::enable_borrowed_range<esi::BitVector> = true;
308
309template <>
310inline constexpr bool
311 std::ranges::enable_borrowed_range<esi::MutableBitVector> = true;
312
313#endif // ESI_VALUES_H
Forward iterator for iterating over bits from LSB (index 0) to MSB.
Definition Values.h:105
std::forward_iterator_tag iterator_category
Definition Values.h:111
bit_iterator & operator++()
Pre-increment: move to next bit.
Definition Values.h:128
std::ptrdiff_t difference_type
Definition Values.h:107
bool operator!=(std::default_sentinel_t sent) const
Sentinel-compatible inequality.
Definition Values.h:161
bool operator<(const bit_iterator &other) const
Less-than comparison (for ranges support).
Definition Values.h:151
bool operator==(const bit_iterator &other) const
Equality comparison.
Definition Values.h:141
bit_iterator()=default
Default constructor.
const BitVector * bitVector
Definition Values.h:166
bool operator==(std::default_sentinel_t) const
Sentinel-compatible equality (for ranges support).
Definition Values.h:156
bit_iterator(const BitVector *bv, size_t pos=0)
Construct an iterator at the given bit position.
Definition Values.h:117
bit_iterator operator++(int)
Post-increment: move to next bit.
Definition Values.h:134
bool operator!=(const bit_iterator &other) const
Inequality comparison.
Definition Values.h:146
bool operator*() const
Dereference: returns the bit value at the current position.
Definition Values.h:121
A lightweight, non-owning bit vector view backed by a byte array span.
Definition Values.h:42
size_t width() const
Definition Values.h:54
friend MutableBitVector operator^(const BitVector &a, const BitVector &b)
Bitwise XOR: creates a new MutableBitVector with the result.
size_t size() const
Definition Values.h:55
size_t bitWidth
Definition Values.h:179
friend MutableBitVector operator&(const BitVector &a, const BitVector &b)
Bitwise AND: creates a new MutableBitVector with the result.
BitVector()=default
BitVector msb(size_t n) const
Return a view of the N most-significant bits.
Definition Values.h:84
uint8_t byte
Definition Values.h:44
BitVector slice(size_t offset, size_t sliceWidth) const
Create a new immutable view of a contiguous bit slice [offset, offset+sliceWidth).
Definition Values.cpp:83
BitVector & operator=(const BitVector &other)
Definition Values.cpp:32
bool getBit(size_t i) const
Return the i-th bit (0 = LSB) as boolean.
Definition Values.cpp:41
BitVector lsb(size_t n) const
Return a view of the N least-significant bits.
Definition Values.h:81
std::string toString(unsigned base=16) const
Definition Values.cpp:362
bit_iterator begin() const
Return an iterator to the first bit (LSB).
Definition Values.h:171
bool operator!=(const BitVector &rhs) const
Definition Values.h:93
std::span< const byte > data
Definition Values.h:178
BitVector & operator>>=(size_t n)
Definition Values.cpp:78
BitVector operator>>(size_t n) const
Logical right shift that drops the least-significant n bits by advancing the byte/bit index and reduc...
Definition Values.cpp:50
uint8_t bitIndex
Definition Values.h:180
bool operator==(const BitVector &rhs) const
Definition Values.cpp:420
bit_iterator end() const
Return an iterator past the last bit.
Definition Values.h:174
std::span< const byte > getSpan() const
Return a handle to the underlying span.
Definition Values.h:62
friend MutableBitVector operator|(const BitVector &a, const BitVector &b)
Bitwise OR: creates a new MutableBitVector with the result.
int64_t toI64() const
Definition Values.cpp:498
Int()=default
static void fits(int64_t v, unsigned n)
Definition Values.cpp:521
T toInt() const
Definition Values.h:261
A mutable bit vector that owns its underlying storage.
Definition Values.h:185
MutableBitVector & operator|=(const MutableBitVector &other)
Definition Values.cpp:456
MutableBitVector & operator>>=(size_t n)
In-place logical right shift that drops the least-significant n bits.
Definition Values.cpp:191
std::vector< uint8_t > takeStorage()
Return and transfer ownership of the underlying storage.
Definition Values.h:219
MutableBitVector & operator<<=(size_t n)
In-place logical left shift shifts in n zero bits at LSB, shifting existing bits upward.
Definition Values.cpp:211
MutableBitVector operator~() const
Definition Values.cpp:471
std::span< const byte > getSpan() const
Return a handle to the underlying span (always aligned since bitIndex=0).
Definition Values.h:216
MutableBitVector & operator&=(const MutableBitVector &other)
Definition Values.cpp:448
MutableBitVector()=default
std::vector< byte > owner
Definition Values.h:243
void setBit(size_t i, bool v)
Set the i-th bit.
Definition Values.cpp:178
MutableBitVector & operator=(const MutableBitVector &other)
Definition Values.cpp:154
MutableBitVector & operator^=(const MutableBitVector &other)
Definition Values.cpp:464
static void fits(uint64_t v, unsigned n)
Definition Values.cpp:545
UInt()=default
uint64_t toUI64() const
Definition Values.cpp:531
T toUInt() const
Definition Values.h:294
Definition esi.py:1
std::ostream & operator<<(std::ostream &os, const BitVector &bv)
Definition Values.cpp:386