diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 500d1a7c1..9dadf7ccb 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4448,9 +4448,7 @@ RTLIL::SigSpec::SigSpec(std::initializer_list parts) { cover("kernel.rtlil.sigspec.init.list"); - width_ = 0; - hash_ = 0; - + init_empty_bits(); log_assert(parts.size() > 0); auto ie = parts.begin(); auto it = ie + parts.size() - 1; @@ -4463,12 +4461,11 @@ RTLIL::SigSpec::SigSpec(const RTLIL::Const &value) cover("kernel.rtlil.sigspec.init.const"); if (GetSize(value) != 0) { - chunks_.emplace_back(value); - width_ = chunks_.back().width; + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(value); } else { - width_ = 0; + init_empty_bits(); } - hash_ = 0; check(); } @@ -4477,12 +4474,11 @@ RTLIL::SigSpec::SigSpec(RTLIL::Const &&value) cover("kernel.rtlil.sigspec.init.const.move"); if (GetSize(value) != 0) { - chunks_.emplace_back(std::move(value)); - width_ = chunks_.back().width; + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(value); } else { - width_ = 0; + init_empty_bits(); } - hash_ = 0; check(); } @@ -4491,12 +4487,11 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk) cover("kernel.rtlil.sigspec.init.chunk"); if (chunk.width != 0) { - chunks_.emplace_back(chunk); - width_ = chunks_.back().width; + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(chunk); } else { - width_ = 0; + init_empty_bits(); } - hash_ = 0; check(); } @@ -4505,12 +4500,11 @@ RTLIL::SigSpec::SigSpec(RTLIL::SigChunk &&chunk) cover("kernel.rtlil.sigspec.init.chunk.move"); if (chunk.width != 0) { - chunks_.emplace_back(std::move(chunk)); - width_ = chunks_.back().width; + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(chunk); } else { - width_ = 0; + init_empty_bits(); } - hash_ = 0; check(); } @@ -4519,12 +4513,11 @@ RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire) cover("kernel.rtlil.sigspec.init.wire"); if (wire->width != 0) { - chunks_.emplace_back(wire); - width_ = chunks_.back().width; + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(wire); } else { - width_ = 0; + init_empty_bits(); } - hash_ = 0; check(); } @@ -4533,12 +4526,11 @@ RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire, int offset, int width) cover("kernel.rtlil.sigspec.init.wire_part"); if (width != 0) { - chunks_.emplace_back(wire, offset, width); - width_ = chunks_.back().width; + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(wire, offset, width); } else { - width_ = 0; + init_empty_bits(); } - hash_ = 0; check(); } @@ -4547,12 +4539,11 @@ RTLIL::SigSpec::SigSpec(const std::string &str) cover("kernel.rtlil.sigspec.init.str"); if (str.size() != 0) { - chunks_.emplace_back(str); - width_ = chunks_.back().width; + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(str); } else { - width_ = 0; + init_empty_bits(); } - hash_ = 0; check(); } @@ -4560,10 +4551,11 @@ RTLIL::SigSpec::SigSpec(int val, int width) { cover("kernel.rtlil.sigspec.init.int"); - if (width != 0) - chunks_.emplace_back(val, width); - width_ = width; - hash_ = 0; + if (width != 0) { + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(val, width); + } else + init_empty_bits(); check(); } @@ -4571,10 +4563,11 @@ RTLIL::SigSpec::SigSpec(RTLIL::State bit, int width) { cover("kernel.rtlil.sigspec.init.state"); - if (width != 0) - chunks_.emplace_back(bit, width); - width_ = width; - hash_ = 0; + if (width != 0) { + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(bit, width); + } else + init_empty_bits(); check(); } @@ -4583,14 +4576,20 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigBit &bit, int width) cover("kernel.rtlil.sigspec.init.bit"); if (width != 0) { - if (bit.wire == NULL) - chunks_.emplace_back(bit.data, width); - else + if (bit.wire == NULL) { + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(bit.data, width); + } else if (width == 1) { + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(bit); + } else { + init_empty_bits(); + bits_.reserve(width); for (int i = 0; i < width; i++) - chunks_.push_back(bit); - } - width_ = width; - hash_ = 0; + bits_.push_back(bit); + } + } else + init_empty_bits(); check(); } @@ -4598,8 +4597,7 @@ RTLIL::SigSpec::SigSpec(const std::vector &chunks) { cover("kernel.rtlil.sigspec.init.stdvec_chunks"); - width_ = 0; - hash_ = 0; + init_empty_bits(); for (const auto &c : chunks) append(c); check(); @@ -4609,8 +4607,7 @@ RTLIL::SigSpec::SigSpec(const std::vector &bits) { cover("kernel.rtlil.sigspec.init.stdvec_bits"); - width_ = 0; - hash_ = 0; + init_empty_bits(); for (const auto &bit : bits) append(bit); check(); @@ -4620,8 +4617,7 @@ RTLIL::SigSpec::SigSpec(const pool &bits) { cover("kernel.rtlil.sigspec.init.pool_bits"); - width_ = 0; - hash_ = 0; + init_empty_bits(); for (const auto &bit : bits) append(bit); check(); @@ -4631,8 +4627,7 @@ RTLIL::SigSpec::SigSpec(const std::set &bits) { cover("kernel.rtlil.sigspec.init.stdset_bits"); - width_ = 0; - hash_ = 0; + init_empty_bits(); for (const auto &bit : bits) append(bit); check(); @@ -4642,9 +4637,8 @@ RTLIL::SigSpec::SigSpec(bool bit) { cover("kernel.rtlil.sigspec.init.bool"); - width_ = 0; - hash_ = 0; - append(SigBit(bit)); + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(bit ? RTLIL::S1 : RTLIL::S0); check(); } @@ -4673,58 +4667,23 @@ void RTLIL::SigSpec::Chunks::const_iterator::next_chunk_bits() chunk.width = i - bit_index; } -void RTLIL::SigSpec::pack() const -{ - RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; - - if (that->bits_.empty()) - return; - - cover("kernel.rtlil.sigspec.convert.pack"); - log_assert(that->chunks_.empty()); - - std::vector old_bits; - old_bits.swap(that->bits_); - - RTLIL::SigChunk *last = NULL; - int last_end_offset = 0; - - for (auto &bit : old_bits) { - if (last && bit.wire == last->wire) { - if (bit.wire == NULL) { - last->data.push_back(bit.data); - last->width++; - continue; - } else if (last_end_offset == bit.offset) { - last_end_offset++; - last->width++; - continue; - } - } - that->chunks_.push_back(bit); - last = &that->chunks_.back(); - last_end_offset = bit.offset + 1; - } - - check(); -} - void RTLIL::SigSpec::unpack() const { - RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; - - if (that->chunks_.empty()) + if (rep_ == BITS) return; + RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; + cover("kernel.rtlil.sigspec.convert.unpack"); - log_assert(that->bits_.empty()); - that->bits_.reserve(that->size()); - for (auto &c : that->chunks_) - for (int i = 0; i < c.width; i++) - that->bits_.emplace_back(c, i); + std::vector bits; + bits.reserve(that->chunk_.width); + for (int i = 0; i < that->chunk_.width; i++) + bits.emplace_back(that->chunk_, i); - that->chunks_.clear(); + that->chunk_.~SigChunk(); + that->rep_ = BITS; + new (&that->bits_) std::vector(std::move(bits)); } void RTLIL::SigSpec::updhash() const @@ -4896,11 +4855,8 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe bits_[i].offset >= pattern_chunk.offset && bits_[i].offset < pattern_chunk.offset + pattern_chunk.width) { bits_.erase(bits_.begin() + i); - width_--; - if (other != NULL) { + if (other != NULL) other->bits_.erase(other->bits_.begin() + i); - other->width_--; - } break; } } @@ -4938,11 +4894,8 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec for (int i = GetSize(bits_) - 1; i >= 0; i--) { if (bits_[i].wire != NULL && pattern.count(bits_[i])) { bits_.erase(bits_.begin() + i); - width_--; - if (other != NULL) { + if (other != NULL) other->bits_.erase(other->bits_.begin() + i); - other->width_--; - } } } hash_ = 0; @@ -4968,11 +4921,8 @@ void RTLIL::SigSpec::remove2(const std::set &pattern, RTLIL::SigS for (int i = GetSize(bits_) - 1; i >= 0; i--) { if (bits_[i].wire != NULL && pattern.count(bits_[i])) { bits_.erase(bits_.begin() + i); - width_--; - if (other != NULL) { + if (other != NULL) other->bits_.erase(other->bits_.begin() + i); - other->width_--; - } } } hash_ = 0; @@ -4998,11 +4948,8 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec * for (int i = GetSize(bits_) - 1; i >= 0; i--) { if (bits_[i].wire != NULL && pattern.count(bits_[i].wire)) { bits_.erase(bits_.begin() + i); - width_--; - if (other != NULL) { + if (other != NULL) other->bits_.erase(other->bits_.begin() + i); - other->width_--; - } } } hash_ = 0; @@ -5100,41 +5047,27 @@ void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with) void RTLIL::SigSpec::remove_const() { - if (packed()) + if (rep_ == CHUNK) { cover("kernel.rtlil.sigspec.remove_const.packed"); - std::vector new_chunks; - new_chunks.reserve(GetSize(chunks_)); - - width_ = 0; - for (auto &chunk : chunks_) - if (chunk.wire != NULL) { - if (!new_chunks.empty() && - new_chunks.back().wire == chunk.wire && - new_chunks.back().offset + new_chunks.back().width == chunk.offset) { - new_chunks.back().width += chunk.width; - } else { - new_chunks.push_back(chunk); - } - width_ += chunk.width; - } - - chunks_.swap(new_chunks); + if (chunk_.wire == NULL) { + chunk_.~SigChunk(); + init_empty_bits(); + } } else { cover("kernel.rtlil.sigspec.remove_const.unpacked"); std::vector new_bits; - new_bits.reserve(width_); + new_bits.reserve(bits_.size()); for (auto &bit : bits_) if (bit.wire != NULL) new_bits.push_back(bit); bits_.swap(new_bits); - width_ = bits_.size(); } hash_ = 0; @@ -5152,7 +5085,6 @@ void RTLIL::SigSpec::remove(int offset, int length) log_assert(offset + length <= size()); bits_.erase(bits_.begin() + offset, bits_.begin() + offset + length); - width_ = bits_.size(); hash_ = 0; check(); @@ -5191,10 +5123,21 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const void RTLIL::SigSpec::rewrite_wires(std::function rewrite) { - pack(); - for (RTLIL::SigChunk &chunk : chunks_) - if (chunk.wire != nullptr) - rewrite(chunk.wire); + if (rep_ == CHUNK) { + if (chunk_.wire != nullptr) + rewrite(chunk_.wire); + return; + } + + std::vector new_bits; + for (const RTLIL::SigChunk &chunk : chunks()) { + RTLIL::SigChunk c = chunk; + if (c.wire != nullptr) + rewrite(c.wire); + for (int i = 0; i < c.width; i++) + new_bits.emplace_back(c, i); + } + bits_ = std::move(new_bits); hash_ = 0; } @@ -5210,60 +5153,54 @@ void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) cover("kernel.rtlil.sigspec.append"); - if (packed()) - for (auto &other_c : signal.chunks()) - { - auto &my_last_c = chunks_.back(); - if (my_last_c.wire == NULL && other_c.wire == NULL) { - auto &this_data = my_last_c.data; - auto &other_data = other_c.data; - this_data.insert(this_data.end(), other_data.begin(), other_data.end()); - my_last_c.width += other_c.width; - } else - if (my_last_c.wire == other_c.wire && my_last_c.offset + my_last_c.width == other_c.offset) { - my_last_c.width += other_c.width; - } else - chunks_.push_back(other_c); + hash_ = 0; + if (rep_ == CHUNK && signal.rep_ == CHUNK && chunk_.wire == signal.chunk_.wire) { + if (chunk_.wire == NULL) { + chunk_.data.insert(chunk_.data.end(), signal.chunk_.data.begin(), signal.chunk_.data.end()); + chunk_.width = GetSize(chunk_.data); + return; + } + if (chunk_.offset + chunk_.width == signal.chunk_.offset) { + chunk_.width += signal.chunk_.width; + return; } - else { - signal.unpack(); - bits_.insert(bits_.end(), signal.bits_.begin(), signal.bits_.end()); } - width_ += signal.size(); - hash_ = 0; + unpack(); + for (const SigBit &bit : signal.bits()) + bits_.push_back(bit); check(); } void RTLIL::SigSpec::append(const RTLIL::SigBit &bit) { - if (packed()) - { + hash_ = 0; + + if (size() == 0) { + destroy(); + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(bit); + return; + } + + if (rep_ == CHUNK && chunk_.wire == bit.wire) { cover("kernel.rtlil.sigspec.append_bit.packed"); - if (chunks_.size() == 0) - chunks_.push_back(bit); - else - if (bit.wire == NULL) - if (chunks_.back().wire == NULL) { - chunks_.back().data.push_back(bit.data); - chunks_.back().width++; - } else - chunks_.push_back(bit); - else - if (chunks_.back().wire == bit.wire && chunks_.back().offset + chunks_.back().width == bit.offset) - chunks_.back().width++; - else - chunks_.push_back(bit); - } - else - { - cover("kernel.rtlil.sigspec.append_bit.unpacked"); - bits_.push_back(bit); + if (chunk_.wire == NULL) { + chunk_.data.push_back(bit.data); + chunk_.width++; + return; + } + if (chunk_.offset + chunk_.width == bit.offset) { + chunk_.width++; + return; + } } - width_++; - hash_ = 0; + unpack(); + + cover("kernel.rtlil.sigspec.append_bit.unpacked"); + bits_.push_back(bit); check(); } @@ -5296,50 +5233,36 @@ RTLIL::SigSpec RTLIL::SigSpec::repeat(int num) const #ifndef NDEBUG void RTLIL::SigSpec::check(Module *mod) const { - if (size() > 64) - { - cover("kernel.rtlil.sigspec.check.skip"); - } - else if (packed()) + if (rep_ == CHUNK) { cover("kernel.rtlil.sigspec.check.packed"); - int w = 0; - for (size_t i = 0; i < chunks_.size(); i++) { - const RTLIL::SigChunk &chunk = chunks_[i]; - log_assert(chunk.width != 0); - if (chunk.wire == NULL) { - if (i > 0) - log_assert(chunks_[i-1].wire != NULL); - log_assert(chunk.offset == 0); - log_assert(chunk.data.size() == (size_t)chunk.width); - } else { - if (i > 0 && chunks_[i-1].wire == chunk.wire) - log_assert(chunk.offset != chunks_[i-1].offset + chunks_[i-1].width); - log_assert(chunk.offset >= 0); - log_assert(chunk.width >= 0); - log_assert(chunk.offset + chunk.width <= chunk.wire->width); - log_assert(chunk.data.size() == 0); - if (mod != nullptr) - log_assert(chunk.wire->module == mod); - } - w += chunk.width; + log_assert(chunk_.width != 0); + if (chunk_.wire == NULL) { + log_assert(chunk_.offset == 0); + log_assert(chunk_.data.size() == (size_t)chunk_.width); + } else { + log_assert(chunk_.offset >= 0); + log_assert(chunk_.width >= 0); + log_assert(chunk_.offset + chunk_.width <= chunk_.wire->width); + log_assert(chunk_.data.size() == 0); + if (mod != nullptr) + log_assert(chunk_.wire->module == mod); } - log_assert(w == size()); - log_assert(bits_.empty()); + } + else if (size() > 64) + { + cover("kernel.rtlil.sigspec.check.skip"); } else { cover("kernel.rtlil.sigspec.check.unpacked"); if (mod != nullptr) { - for (size_t i = 0; i < bits_.size(); i++) - if (bits_[i].wire != nullptr) - log_assert(bits_[i].wire->module == mod); + for (const RTLIL::SigBit &bit : bits_) + if (bit.wire != nullptr) + log_assert(bit.wire->module == mod); } - - log_assert(size() == GetSize(bits_)); - log_assert(chunks_.empty()); } } #endif @@ -5713,7 +5636,7 @@ std::map RTLIL::SigSpec::to_sigbit_map(const RTLIL log_assert(size() == other.size()); std::map new_map; - for (int i = 0; i < width_; i++) + for (int i = 0; i < GetSize(bits_); i++) new_map[bits_[i]] = other.bits_[i]; return new_map; @@ -5730,7 +5653,7 @@ dict RTLIL::SigSpec::to_sigbit_dict(const RTLIL::S dict new_map; new_map.reserve(size()); - for (int i = 0; i < width_; i++) + for (int i = 0; i < GetSize(bits_); i++) new_map[bits_[i]] = other.bits_[i]; return new_map; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index f22c3541c..1265875e3 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1233,29 +1233,53 @@ struct RTLIL::SigSpecConstIterator struct RTLIL::SigSpec { private: - int width_; - Hasher::hash_t hash_; - std::vector chunks_; // LSB at index 0 - std::vector bits_; // LSB at index 0 + enum Representation : char { + CHUNK, + BITS, + }; - void pack() const; - void unpack() const; - void updhash() const; + Representation rep_; + Hasher::hash_t hash_ = 0; + union { + RTLIL::SigChunk chunk_; + std::vector bits_; // LSB at index 0 + }; - inline bool packed() const { - return bits_.empty(); + void init_empty_bits() { + rep_ = BITS; + new (&bits_) std::vector; } + void unpack() const; inline void inline_unpack() const { - if (!chunks_.empty()) + if (rep_ == CHUNK) unpack(); } + void updhash() const; + void destroy() { + if (rep_ == CHUNK) + chunk_.~SigChunk(); + else + bits_.~vector(); + } + friend struct Chunks; + public: - SigSpec() : width_(0), hash_(0) {} + SigSpec() { init_empty_bits(); } SigSpec(std::initializer_list parts); - SigSpec(const SigSpec &value) = default; - SigSpec(SigSpec &&value) = default; + SigSpec(const SigSpec &value) : rep_(value.rep_), hash_(value.hash_) { + if (value.rep_ == CHUNK) + new (&chunk_) RTLIL::SigChunk(value.chunk_); + else + new (&bits_) std::vector(value.bits_); + } + SigSpec(SigSpec &&value) : rep_(value.rep_), hash_(value.hash_) { + if (value.rep_ == CHUNK) + new (&chunk_) RTLIL::SigChunk(std::move(value.chunk_)); + else + new (&bits_) std::vector(std::move(value.bits_)); + } SigSpec(const RTLIL::Const &value); SigSpec(RTLIL::Const &&value); SigSpec(const RTLIL::SigChunk &chunk); @@ -1271,9 +1295,30 @@ public: SigSpec(const pool &bits); SigSpec(const std::set &bits); explicit SigSpec(bool bit); + ~SigSpec() { + destroy(); + } - SigSpec &operator=(const SigSpec &rhs) = default; - SigSpec &operator=(SigSpec &&rhs) = default; + SigSpec &operator=(const SigSpec &rhs) { + destroy(); + rep_ = rhs.rep_; + hash_ = rhs.hash_; + if (rep_ == CHUNK) + new (&chunk_) RTLIL::SigChunk(rhs.chunk_); + else + new (&bits_) std::vector(rhs.bits_); + return *this; + } + SigSpec &operator=(SigSpec &&rhs) { + destroy(); + rep_ = rhs.rep_; + hash_ = rhs.hash_; + if (rep_ == CHUNK) + new (&chunk_) RTLIL::SigChunk(std::move(rhs.chunk_)); + else + new (&bits_) std::vector(std::move(rhs.bits_)); + return *this; + } struct Chunks { Chunks(const SigSpec &spec) : spec(spec) {} @@ -1285,28 +1330,25 @@ public: using reference = const SigChunk &; const SigSpec &spec; - int chunk_index; int bit_index; SigChunk chunk; const_iterator(const SigSpec &spec) : spec(spec) { - chunk_index = 0; bit_index = 0; - if (!spec.packed()) + if (spec.rep_ == BITS) next_chunk_bits(); } void next_chunk_bits(); const SigChunk &operator*() { - if (spec.packed()) - return spec.chunks_[chunk_index]; + if (spec.rep_ == CHUNK) + return spec.chunk_; return chunk; }; const SigChunk *operator->() { return &**this; } const_iterator &operator++() { bit_index += (**this).width; - ++chunk_index; - if (!spec.packed()) + if (spec.rep_ == BITS) next_chunk_bits(); return *this; } @@ -1362,7 +1404,7 @@ public: inline Chunks chunks() const { return {*this}; } inline const std::vector &bits() const { inline_unpack(); return bits_; } - inline int size() const { return width_; } + inline int size() const { return rep_ == CHUNK ? chunk_.width : GetSize(bits_); } inline bool empty() const { return size() == 0; } inline RTLIL::SigBit &operator[](int index) { inline_unpack(); hash_ = 0; return bits_.at(index); }