3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-11-05 13:56:04 +00:00

Make SigSpecConstIterator iterate over SigSpec without unpacking

To make this efficient, the iterator keeps `chunk_index_hint` pointing to
the current chunk. This is only a hint, since it is not possible to maintain
its validity if the `SigSpec` representation is temporarily changed to unpacked.
In that case we have to resync using binary search.
This commit is contained in:
Robert O'Callahan 2025-09-01 04:49:29 +00:00
parent acee6db361
commit e49f9765a2
3 changed files with 105 additions and 10 deletions

View file

@ -1217,18 +1217,29 @@ struct RTLIL::SigSpecIterator
struct RTLIL::SigSpecConstIterator
{
typedef std::input_iterator_tag iterator_category;
typedef RTLIL::SigBit value_type;
typedef const RTLIL::SigBit& value_type;
typedef ptrdiff_t difference_type;
typedef RTLIL::SigBit* pointer;
typedef RTLIL::SigBit& reference;
const RTLIL::SigSpec *sig_p;
int index;
SigBit bit;
int bit_index;
// Index of chunk containing bit_index, or GetSize(chunks_) if bit_index == width_.
// or 0 if *sig_p is not packed. This is a hint and may be incorrect in unusual
// circumstances, e.g. when the SigSpec changes from unpacked to packed
// during iteration.
int chunk_index_hint;
inline const RTLIL::SigBit &operator*() const;
inline bool operator!=(const RTLIL::SigSpecConstIterator &other) const { return index != other.index; }
inline bool operator==(const RTLIL::SigSpecIterator &other) const { return index == other.index; }
inline void operator++() { index++; }
inline const RTLIL::SigBit &operator*();
inline bool operator!=(const RTLIL::SigSpecConstIterator &other) const { return !(*this == other); }
inline bool operator==(const RTLIL::SigSpecConstIterator &other) const { return bit_index == other.bit_index; }
inline void operator++();
private:
// Must be called when sig_p is packed and `bit_index` is in range. Finds the chunk containing `bit_index`
// and sets chunk_index_hint.
const RTLIL::SigChunk &find_chunk();
};
struct RTLIL::SigSpec
@ -1255,6 +1266,7 @@ private:
// Only used by Module::remove(const pool<Wire*> &wires)
// but cannot be more specific as it isn't yet declared
friend struct RTLIL::Module;
friend struct RTLIL::SigSpecConstIterator;
public:
SigSpec() : width_(0), hash_(0) {}
@ -1292,8 +1304,20 @@ public:
inline RTLIL::SigSpecIterator begin() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = 0; return it; }
inline RTLIL::SigSpecIterator end() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = width_; return it; }
inline RTLIL::SigSpecConstIterator begin() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = 0; return it; }
inline RTLIL::SigSpecConstIterator end() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = width_; return it; }
inline RTLIL::SigSpecConstIterator begin() const {
RTLIL::SigSpecConstIterator it;
it.sig_p = this;
it.bit_index = 0;
it.chunk_index_hint = 0;
return it;
}
inline RTLIL::SigSpecConstIterator end() const {
RTLIL::SigSpecConstIterator it;
it.sig_p = this;
it.bit_index = width_;
it.chunk_index_hint = GetSize(chunks_);
return it;
}
void sort();
void sort_and_unify();
@ -2313,8 +2337,30 @@ inline RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const {
return (*sig_p)[index];
}
inline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() const {
return (*sig_p)[index];
inline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() {
if (!sig_p->packed())
return sig_p->bits_.at(bit_index);
if (chunk_index_hint < GetSize(sig_p->chunks_)) {
const SigChunk &chunk = sig_p->chunks_[chunk_index_hint];
if (chunk.offset_in_sigspec <= bit_index && bit_index < chunk.offset_in_sigspec + chunk.width) {
bit = chunk[bit_index - chunk.offset_in_sigspec];
return bit;
}
}
const SigChunk &chunk = find_chunk();
bit = chunk[bit_index - chunk.offset_in_sigspec];
return bit;
}
inline void RTLIL::SigSpecConstIterator::operator++() {
++bit_index;
if (!sig_p->packed())
return;
if (chunk_index_hint < GetSize(sig_p->chunks_)) {
const SigChunk &chunk = sig_p->chunks_[chunk_index_hint];
if (chunk.offset_in_sigspec + chunk.width == bit_index)
++chunk_index_hint;
}
}
inline RTLIL::SigBit::SigBit(const RTLIL::SigSpec &sig) {