From e151fbc5df0b1ce0c018e535c1c97e723d2aebc2 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 28 Aug 2025 01:54:41 +0000 Subject: [PATCH] Update Const API with alternatives to direct use of bits() In particular, `Const::resize()`, `Const::set()`, and `Const::iterator`. --- kernel/rtlil.h | 81 ++++++++++++++++++++++++++++++++-- tests/unit/kernel/rtlilTest.cc | 54 +++++++++++++++++++++++ 2 files changed, 131 insertions(+), 4 deletions(-) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index f2279645e..d3392df8d 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -743,13 +743,24 @@ public: Const(const std::string &str); Const(long long val, int width = 32); Const(RTLIL::State bit, int width = 1); - Const(const std::vector &bits) : flags(RTLIL::CONST_FLAG_NONE), tag(backing_tag::bits), bits_(bits) {} + Const(std::vector bits) : flags(RTLIL::CONST_FLAG_NONE), tag(backing_tag::bits), bits_(std::move(bits)) {} Const(const std::vector &bits); Const(const RTLIL::Const &other); Const(RTLIL::Const &&other); RTLIL::Const &operator =(const RTLIL::Const &other); ~Const(); + struct Builder + { + Builder() {} + Builder(int expected_width) { bits.reserve(expected_width); } + void push_back(RTLIL::State b) { bits.push_back(b); } + int size() const { return static_cast(bits.size()); } + Const build() { return Const(std::move(bits)); } + private: + std::vector bits; + }; + bool operator <(const RTLIL::Const &other) const; bool operator ==(const RTLIL::Const &other) const; bool operator !=(const RTLIL::Const &other) const; @@ -786,6 +797,12 @@ public: void bitvectorize() const; void append(const RTLIL::Const &other); + void set(int i, RTLIL::State state) { + bits()[i] = state; + } + void resize(int size, RTLIL::State fill) { + bits().resize(size, fill); + } class const_iterator { private: @@ -828,12 +845,69 @@ public: } }; + class iterator { + private: + Const* parent; + size_t idx; + + public: + class proxy { + private: + Const* parent; + size_t idx; + public: + proxy(Const* parent, size_t idx) : parent(parent), idx(idx) {} + operator State() const { return (*parent)[idx]; } + proxy& operator=(State s) { parent->set(idx, s); return *this; } + proxy& operator=(const proxy& other) { parent->set(idx, (*other.parent)[other.idx]); return *this; } + }; + + using iterator_category = std::bidirectional_iterator_tag; + using value_type = State; + using difference_type = std::ptrdiff_t; + using pointer = proxy*; + using reference = proxy; + + iterator(Const& c, size_t i) : parent(&c), idx(i) {} + + proxy operator*() const { return proxy(parent, idx); } + iterator& operator++() { ++idx; return *this; } + iterator& operator--() { --idx; return *this; } + iterator operator++(int) { iterator result(*this); ++idx; return result; } + iterator operator--(int) { iterator result(*this); --idx; return result; } + iterator& operator+=(int i) { idx += i; return *this; } + + iterator operator+(int add) { + return iterator(*parent, idx + add); + } + iterator operator-(int sub) { + return iterator(*parent, idx - sub); + } + int operator-(const iterator& other) { + return idx - other.idx; + } + + bool operator==(const iterator& other) const { + return idx == other.idx; + } + + bool operator!=(const iterator& other) const { + return !(*this == other); + } + }; + const_iterator begin() const { return const_iterator(*this, 0); } const_iterator end() const { return const_iterator(*this, size()); } + iterator begin() { + return iterator(*this, 0); + } + iterator end() { + return iterator(*this, size()); + } State back() const { return *(end() - 1); } @@ -865,12 +939,11 @@ public: std::optional as_int_compress(bool is_signed) const; void extu(int width) { - bits().resize(width, RTLIL::State::S0); + resize(width, RTLIL::State::S0); } void exts(int width) { - bitvectype& bv = bits(); - bv.resize(width, bv.empty() ? RTLIL::State::Sx : bv.back()); + resize(width, empty() ? RTLIL::State::Sx : back()); } [[nodiscard]] Hasher hash_into(Hasher h) const { diff --git a/tests/unit/kernel/rtlilTest.cc b/tests/unit/kernel/rtlilTest.cc index b8ac554b1..6a5f75a95 100644 --- a/tests/unit/kernel/rtlilTest.cc +++ b/tests/unit/kernel/rtlilTest.cc @@ -114,6 +114,60 @@ namespace RTLIL { EXPECT_EQ(*it++, State::S0); } + TEST_F(KernelRtlilTest, ConstIteratorWorks) { + Const c(0x2, 2); + Const::iterator it = c.begin(); + ASSERT_NE(it, c.end()); + EXPECT_EQ(*it, State::S0); + ++it; + ASSERT_NE(it, c.end()); + EXPECT_EQ(*it, State::S1); + ++it; + ASSERT_EQ(it, c.end()); + } + + TEST_F(KernelRtlilTest, ConstIteratorPreincrement) { + Const c(0x2, 2); + Const::iterator it = c.begin(); + EXPECT_EQ(*++it, State::S1); + } + + TEST_F(KernelRtlilTest, ConstIteratorPostincrement) { + Const c(0x2, 2); + Const::iterator it = c.begin(); + EXPECT_EQ(*it++, State::S0); + } + + TEST_F(KernelRtlilTest, ConstIteratorWriteWorks) { + Const c(0x2, 2); + Const::iterator it = c.begin(); + EXPECT_EQ(*it, State::S0); + *it = State::S1; + EXPECT_EQ(*it, State::S1); + } + + TEST_F(KernelRtlilTest, ConstBuilder) { + Const::Builder b; + EXPECT_EQ(GetSize(b), 0); + b.push_back(S0); + EXPECT_EQ(GetSize(b), 1); + b.push_back(S1); + EXPECT_EQ(GetSize(b), 2); + EXPECT_EQ(b.build(), Const(0x2, 2)); + } + + TEST_F(KernelRtlilTest, ConstSet) { + Const c(0x2, 2); + c.set(0, S1); + EXPECT_EQ(c, Const(0x3, 2)); + } + + TEST_F(KernelRtlilTest, ConstResize) { + Const c(0x2, 2); + c.resize(4, S1); + EXPECT_EQ(c, Const(0xe, 4)); + } + class WireRtlVsHdlIndexConversionTest : public KernelRtlilTest, public testing::WithParamInterface>