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:
parent
acee6db361
commit
e49f9765a2
3 changed files with 105 additions and 10 deletions
|
|
@ -4447,6 +4447,23 @@ bool RTLIL::SigChunk::operator !=(const RTLIL::SigChunk &other) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const RTLIL::SigChunk &RTLIL::SigSpecConstIterator::find_chunk()
|
||||||
|
{
|
||||||
|
int low = 0;
|
||||||
|
int high = GetSize(sig_p->chunks_);
|
||||||
|
while (high - low >= 2) {
|
||||||
|
int mid = (low + high) / 2;
|
||||||
|
if (sig_p->chunks_[mid].offset_in_sigspec <= bit_index)
|
||||||
|
low = mid;
|
||||||
|
else
|
||||||
|
high = mid;
|
||||||
|
}
|
||||||
|
chunk_index_hint = low;
|
||||||
|
const RTLIL::SigChunk &chunk = sig_p->chunks_[chunk_index_hint];
|
||||||
|
log_assert(chunk.offset_in_sigspec <= bit_index && bit_index < chunk.offset_in_sigspec + chunk.width);
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
RTLIL::SigSpec::SigSpec(std::initializer_list<RTLIL::SigSpec> parts)
|
RTLIL::SigSpec::SigSpec(std::initializer_list<RTLIL::SigSpec> parts)
|
||||||
{
|
{
|
||||||
cover("kernel.rtlil.sigspec.init.list");
|
cover("kernel.rtlil.sigspec.init.list");
|
||||||
|
|
|
||||||
|
|
@ -1217,18 +1217,29 @@ struct RTLIL::SigSpecIterator
|
||||||
struct RTLIL::SigSpecConstIterator
|
struct RTLIL::SigSpecConstIterator
|
||||||
{
|
{
|
||||||
typedef std::input_iterator_tag iterator_category;
|
typedef std::input_iterator_tag iterator_category;
|
||||||
typedef RTLIL::SigBit value_type;
|
typedef const RTLIL::SigBit& value_type;
|
||||||
typedef ptrdiff_t difference_type;
|
typedef ptrdiff_t difference_type;
|
||||||
typedef RTLIL::SigBit* pointer;
|
typedef RTLIL::SigBit* pointer;
|
||||||
typedef RTLIL::SigBit& reference;
|
typedef RTLIL::SigBit& reference;
|
||||||
|
|
||||||
const RTLIL::SigSpec *sig_p;
|
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 const RTLIL::SigBit &operator*();
|
||||||
inline bool operator!=(const RTLIL::SigSpecConstIterator &other) const { return index != other.index; }
|
inline bool operator!=(const RTLIL::SigSpecConstIterator &other) const { return !(*this == other); }
|
||||||
inline bool operator==(const RTLIL::SigSpecIterator &other) const { return index == other.index; }
|
inline bool operator==(const RTLIL::SigSpecConstIterator &other) const { return bit_index == other.bit_index; }
|
||||||
inline void operator++() { 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
|
struct RTLIL::SigSpec
|
||||||
|
|
@ -1255,6 +1266,7 @@ private:
|
||||||
// Only used by Module::remove(const pool<Wire*> &wires)
|
// Only used by Module::remove(const pool<Wire*> &wires)
|
||||||
// but cannot be more specific as it isn't yet declared
|
// but cannot be more specific as it isn't yet declared
|
||||||
friend struct RTLIL::Module;
|
friend struct RTLIL::Module;
|
||||||
|
friend struct RTLIL::SigSpecConstIterator;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SigSpec() : width_(0), hash_(0) {}
|
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 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::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 begin() const {
|
||||||
inline RTLIL::SigSpecConstIterator end() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = width_; return it; }
|
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();
|
||||||
void sort_and_unify();
|
void sort_and_unify();
|
||||||
|
|
@ -2313,8 +2337,30 @@ inline RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const {
|
||||||
return (*sig_p)[index];
|
return (*sig_p)[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() const {
|
inline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() {
|
||||||
return (*sig_p)[index];
|
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) {
|
inline RTLIL::SigBit::SigBit(const RTLIL::SigSpec &sig) {
|
||||||
|
|
|
||||||
|
|
@ -361,6 +361,38 @@ namespace RTLIL {
|
||||||
EXPECT_FALSE(Const().is_onehot(&pos));
|
EXPECT_FALSE(Const().is_onehot(&pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(KernelRtlilTest, SigSpecConstIteratorRepresentationChange) {
|
||||||
|
std::unique_ptr<Module> mod = std::make_unique<Module>();
|
||||||
|
std::vector<Wire*> wires;
|
||||||
|
SigSpec spec;
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
wires.push_back(mod->addWire(IdString(stringf("\\test%d", i)), 10));
|
||||||
|
spec.append(wires.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
const SigSpec &const_spec = spec;
|
||||||
|
SigSpecConstIterator it = const_spec.begin();
|
||||||
|
for (int i = 0; i < 55; ++i)
|
||||||
|
++it;
|
||||||
|
EXPECT_EQ(*it, SigBit(wires[5], 5));
|
||||||
|
|
||||||
|
// Force unpacking of the spec.
|
||||||
|
EXPECT_EQ(spec[55], SigBit(wires[5], 5));
|
||||||
|
// Make sure the iterator is still OK
|
||||||
|
EXPECT_EQ(*it, SigBit(wires[5], 5));
|
||||||
|
|
||||||
|
// Advance iterator while unpacked
|
||||||
|
for (int i = 0; i < 20; ++i)
|
||||||
|
++it;
|
||||||
|
EXPECT_EQ(*it, SigBit(wires[7], 5));
|
||||||
|
|
||||||
|
// Force packing of the spec.
|
||||||
|
SigSpec other = spec;
|
||||||
|
EXPECT_FALSE(spec < other);
|
||||||
|
// Make sure iterator is still OK
|
||||||
|
EXPECT_EQ(*it, SigBit(wires[7], 5));
|
||||||
|
}
|
||||||
|
|
||||||
class WireRtlVsHdlIndexConversionTest :
|
class WireRtlVsHdlIndexConversionTest :
|
||||||
public KernelRtlilTest,
|
public KernelRtlilTest,
|
||||||
public testing::WithParamInterface<std::tuple<bool, int, int>>
|
public testing::WithParamInterface<std::tuple<bool, int, int>>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue