Compare commits

...

33 Commits

Author SHA1 Message Date
Robert O'Callahan 7db64427c0
Merge 0d3cd5d6c8 into 691d6b8508 2025-11-06 21:40:26 +01:00
Miodrag Milanović 691d6b8508
Merge pull request #5469 from YosysHQ/update_abc
Update ABC
2025-11-06 21:19:39 +01:00
Miodrag Milanovic 75ce33c7b2 Update ABC 2025-11-06 09:54:47 +01:00
Robert O'Callahan 0d3cd5d6c8 Implement SigSpec::updhash() using a relaxed atomic for thread-safety 2025-10-31 11:53:39 +00:00
Robert O'Callahan 45017e19ec Make SigSpec::unpack() non-const 2025-10-31 11:53:39 +00:00
Robert O'Callahan 9a2fd4c31b Switch the SigSpec packed representation to allow just a single chunk that's inline in the SigSpec.
Single-chunk SigSpecs are very common and this avoids a heap allocation. It also simplifies
some algorithms.
2025-10-31 11:53:39 +00:00
Robert O'Callahan 1af5d4f2db Use chunks iterator for SigSpec::extract() 2025-10-31 11:53:39 +00:00
Robert O'Callahan ab525643a7 Don't reset the hash when unpacking, instead clear the hash whenever bits are modified 2025-10-31 11:53:39 +00:00
Robert O'Callahan a1f7d6c9bf Use size() instead of direct access to width_ in many places 2025-10-31 11:53:39 +00:00
Robert O'Callahan dbb8354996 Remove unnecessary pack() from SigSpec::extend_u0() 2025-10-31 11:53:39 +00:00
Robert O'Callahan d314c47a55 Simplify SigSpec::as_bit() 2025-10-31 11:53:39 +00:00
Robert O'Callahan be530bef73 Instead of using packing and hashing to compute SigSpec ordering and equality, just use the width and chunkwise comparisons
This avoids having to pack and compute hashes, and generally results in a
simpler ordering.
2025-10-31 11:53:39 +00:00
Robert O'Callahan 973e8a3928 Build a temporary SigChunk list in the iterator in the cases where that's needed 2025-10-31 11:53:39 +00:00
Robert O'Callahan 8c9dd3209a Make SigSpec conversion to vector of SigChunk use chunks iterator 2025-10-31 11:53:39 +00:00
Robert O'Callahan 4672127610 Make SigSpec::parse_rhs use is_chunk to avoid direct access to chunks_ 2025-10-31 11:53:39 +00:00
Robert O'Callahan 11a91af920 Make SigSpec::to_sigbit_pool use chunk iterator 2025-10-31 11:53:39 +00:00
Robert O'Callahan 8cb7cd7ac1 Make SigSpec::to_sigbit_set use chunk iterator 2025-10-31 11:53:39 +00:00
Robert O'Callahan 82f86164d3 Use SigSpec::try_as_const in some places 2025-10-31 11:53:39 +00:00
Robert O'Callahan 0d45d9cc6e Make SigSpec::is_one_hot use try_as_const 2025-10-31 11:53:39 +00:00
Robert O'Callahan a0e9e2d364 Fix try_as_const/as_wire/as_chunk 2025-10-31 11:53:39 +00:00
Robert O'Callahan 000c081965 Add try_as_const and use the const iterator a bit more 2025-10-31 11:53:38 +00:00
Robert O'Callahan 04a6dbc562 Make SigSpec::has_marked_bits use chunk iterator 2025-10-31 11:53:38 +00:00
Robert O'Callahan 7bd6b4f287 Make SigSpec::has_const(State) use chunk iterator 2025-10-31 11:53:38 +00:00
Robert O'Callahan 213d665ae1 Make SigSpec::has_const use chunk iterator 2025-10-31 11:53:38 +00:00
Robert O'Callahan 5c8f9f14ca Make SigSpec::is_fully_undef use chunk iterator 2025-10-31 11:53:38 +00:00
Robert O'Callahan b2de56cae2 Make SigSpec::is_fully_def use chunk iterator 2025-10-31 11:53:38 +00:00
Robert O'Callahan 8a88acd9b8 Make SigSpec::is_fully_ones use chunk iterator 2025-10-31 11:53:38 +00:00
Robert O'Callahan 58dbf75885 Make SigSpec::is_fully_zero use chunk iterator 2025-10-31 11:53:38 +00:00
Robert O'Callahan 20e64ee17b Make is_fully_const use chunk iterator 2025-10-31 11:53:38 +00:00
Robert O'Callahan bf4cfbd72d Make SigSpec::is_wire/is_chunk/is_fully_const use chunk iterator 2025-10-31 11:53:38 +00:00
Robert O'Callahan fd7b4f4a8b Make SigSpec::updhash() use chunk iterator 2025-10-31 11:53:38 +00:00
Robert O'Callahan 37e4c2e8f8 Make SigSpec::chunks() return an object that can be iterated over without packing the SigSpec 2025-10-31 11:53:38 +00:00
Robert O'Callahan c4f3e61339 Make Module stop accessing internals of SigSpec 2025-10-29 18:32:10 +00:00
8 changed files with 669 additions and 551 deletions

2
abc

@ -1 +1 @@
Subproject commit fa186342baefea06e7c2aa13fe51f338ffc84912
Subproject commit 1c5ed1ce378cc04beac30bb31abc4c37c8467042

View File

@ -121,7 +121,8 @@ void RTLIL_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, boo
dump_sigchunk(f, sig.as_chunk(), autoint);
} else {
f << stringf("{ ");
for (const auto& chunk : reversed(sig.chunks())) {
auto chunks = sig.chunks();
for (const auto& chunk : reversed(chunks)) {
dump_sigchunk(f, chunk, false);
f << stringf(" ");
}

View File

@ -382,8 +382,9 @@ void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
dump_sigchunk(f, sig.as_chunk());
} else {
f << stringf("{ ");
for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); ++it) {
if (it != sig.chunks().rbegin())
auto chunks = sig.chunks();
for (auto it = chunks.rbegin(); it != chunks.rend(); ++it) {
if (it != chunks.rbegin())
f << stringf(", ");
dump_sigchunk(f, *it, true);
}

File diff suppressed because it is too large Load Diff

View File

@ -1223,9 +1223,10 @@ struct RTLIL::SigSpecConstIterator
typedef RTLIL::SigBit& reference;
const RTLIL::SigSpec *sig_p;
RTLIL::SigBit bit;
int index;
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::SigSpecIterator &other) const { return index == other.index; }
inline void operator++() { index++; }
@ -1234,33 +1235,83 @@ struct RTLIL::SigSpecConstIterator
struct RTLIL::SigSpec
{
private:
int width_;
Hasher::hash_t hash_;
std::vector<RTLIL::SigChunk> chunks_; // LSB at index 0
std::vector<RTLIL::SigBit> bits_; // LSB at index 0
enum Representation : char {
CHUNK,
BITS,
};
// An AtomicHash is either clear or a nonzero integer.
struct AtomicHash {
// Create an initially clear value.
AtomicHash() : atomic_(0) {}
AtomicHash(const AtomicHash &rhs) : atomic_(rhs.load()) {}
AtomicHash &operator=(const AtomicHash &rhs) { store(rhs.load()); return *this; }
// Read the hash. Returns nullopt if the hash is clear.
std::optional<Hasher::hash_t> read() const {
Hasher::hash_t value = load();
if (value == 0)
return std::nullopt;
return value;
}
// Set the hash. If the value is already set, then the new value must
// equal the current value.
void set(Hasher::hash_t value) const {
log_assert(value != 0);
Hasher::hash_t old = const_cast<std::atomic<Hasher::hash_t>&>(atomic_)
.exchange(value, std::memory_order_relaxed);
log_assert(old == 0 || old == value);
}
void clear() { store(0); }
private:
int load() const { return atomic_.load(std::memory_order_relaxed); }
void store(Hasher::hash_t value) const {
const_cast<std::atomic<Hasher::hash_t>&>(atomic_).store(value, std::memory_order_relaxed);
}
void pack() const;
void unpack() const;
void updhash() const;
std::atomic<Hasher::hash_t> atomic_;
};
inline bool packed() const {
return bits_.empty();
Representation rep_;
AtomicHash hash_;
union {
RTLIL::SigChunk chunk_;
std::vector<RTLIL::SigBit> bits_; // LSB at index 0
};
void init_empty_bits() {
rep_ = BITS;
new (&bits_) std::vector<RTLIL::SigBit>;
}
inline void inline_unpack() const {
if (!chunks_.empty())
void unpack();
inline void inline_unpack() {
if (rep_ == CHUNK)
unpack();
}
// Only used by Module::remove(const pool<Wire*> &wires)
// but cannot be more specific as it isn't yet declared
friend struct RTLIL::Module;
Hasher::hash_t 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<RTLIL::SigSpec> 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<RTLIL::SigBit>(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<RTLIL::SigBit>(std::move(value.bits_));
}
SigSpec(const RTLIL::Const &value);
SigSpec(RTLIL::Const &&value);
SigSpec(const RTLIL::SigChunk &chunk);
@ -1276,24 +1327,135 @@ public:
SigSpec(const pool<RTLIL::SigBit> &bits);
SigSpec(const std::set<RTLIL::SigBit> &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<RTLIL::SigBit>(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<RTLIL::SigBit>(std::move(rhs.bits_));
return *this;
}
inline const std::vector<RTLIL::SigChunk> &chunks() const { pack(); return chunks_; }
inline const std::vector<RTLIL::SigBit> &bits() const { inline_unpack(); return bits_; }
struct Chunks {
Chunks(const SigSpec &spec) : spec(spec) {}
struct const_iterator {
using iterator_category = std::forward_iterator_tag;
using value_type = const SigChunk &;
using difference_type = std::ptrdiff_t;
using pointer = const SigChunk *;
using reference = const SigChunk &;
inline int size() const { return width_; }
inline bool empty() const { return width_ == 0; }
const SigSpec &spec;
int bit_index;
SigChunk chunk;
inline RTLIL::SigBit &operator[](int index) { inline_unpack(); return bits_.at(index); }
inline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return bits_.at(index); }
const_iterator(const SigSpec &spec) : spec(spec) {
bit_index = 0;
if (spec.rep_ == BITS)
next_chunk_bits();
}
void next_chunk_bits();
const SigChunk &operator*() {
if (spec.rep_ == CHUNK)
return spec.chunk_;
return chunk;
};
const SigChunk *operator->() { return &**this; }
const_iterator &operator++() {
bit_index += (**this).width;
if (spec.rep_ == BITS)
next_chunk_bits();
return *this;
}
bool operator==(const const_iterator &rhs) const { return bit_index == rhs.bit_index; }
bool operator!=(const const_iterator &rhs) const { return !(*this == rhs); }
};
const_iterator begin() const { return const_iterator(spec); }
const_iterator end() const {
const_iterator it(spec);
it.bit_index = spec.size();
return it;
}
// Later we should deprecate these and remove their in-tree calls,
// so we can eventually remove chunk_vector.
std::vector<RTLIL::SigChunk>::const_reverse_iterator rbegin() {
ensure_chunk_vector();
return chunk_vector.rbegin();
}
std::vector<RTLIL::SigChunk>::const_reverse_iterator rend() {
ensure_chunk_vector();
return chunk_vector.rend();
}
int size() {
ensure_chunk_vector();
return chunk_vector.size();
}
int size() const {
int result = 0;
for (const SigChunk &_: *this)
++result;
return result;
}
const SigChunk &at(int index) {
ensure_chunk_vector();
return chunk_vector.at(index);
}
operator const std::vector<RTLIL::SigChunk>&() {
ensure_chunk_vector();
return chunk_vector;
}
private:
void ensure_chunk_vector() {
if (spec.size() > 0 && chunk_vector.empty()) {
for (const RTLIL::SigChunk &c : *this)
chunk_vector.push_back(c);
}
}
const SigSpec &spec;
std::vector<RTLIL::SigChunk> chunk_vector;
};
friend struct Chunks::const_iterator;
inline Chunks chunks() const { return {*this}; }
inline const SigSpec &bits() const { return *this; }
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_.clear(); return bits_.at(index); }
inline RTLIL::SigBit operator[](int index) const {
if (rep_ == CHUNK) {
if (index < 0 || index >= chunk_.width)
throw std::out_of_range("SigSpec::operator[]");
if (chunk_.wire)
return RTLIL::SigBit(chunk_.wire, chunk_.offset + index);
return RTLIL::SigBit(chunk_.data[index]);
}
return bits_.at(index);
}
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 = size(); 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 end() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = size(); return it; }
void sort();
void sort_and_unify();
@ -1325,10 +1487,14 @@ public:
RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const;
RTLIL::SigSpec extract(const pool<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other = NULL) const;
RTLIL::SigSpec extract(int offset, int length = 1) const;
RTLIL::SigSpec extract_end(int offset) const { return extract(offset, width_ - offset); }
RTLIL::SigSpec extract_end(int offset) const { return extract(offset, size() - offset); }
RTLIL::SigBit lsb() const { log_assert(width_); return (*this)[0]; };
RTLIL::SigBit msb() const { log_assert(width_); return (*this)[width_ - 1]; };
void rewrite_wires(std::function<void(RTLIL::Wire*& wire)> rewrite);
RTLIL::SigBit lsb() const { log_assert(size()); return (*this)[0]; };
RTLIL::SigBit msb() const { log_assert(size()); return (*this)[size() - 1]; };
RTLIL::SigBit front() const { return (*this)[0]; }
RTLIL::SigBit back() const { return (*this)[size() - 1]; }
void append(const RTLIL::SigSpec &signal);
inline void append(Wire *wire) { append(RTLIL::SigSpec(wire)); }
@ -1351,7 +1517,7 @@ public:
bool is_wire() const;
bool is_chunk() const;
inline bool is_bit() const { return width_ == 1; }
inline bool is_bit() const { return size() == 1; }
bool known_driver() const;
@ -1388,6 +1554,9 @@ public:
int as_int_saturating(bool is_signed = false) const;
std::string as_string() const;
// Returns std::nullopt if there are any non-constant bits. Returns an empty
// Const if this has zero width.
std::optional<RTLIL::Const> try_as_const() const;
RTLIL::Const as_const() const;
RTLIL::Wire *as_wire() const;
RTLIL::SigChunk as_chunk() const;
@ -1405,11 +1574,19 @@ public:
static bool parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL::Module *module, std::string str);
static bool parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str);
operator std::vector<RTLIL::SigChunk>() const { return chunks(); }
operator std::vector<RTLIL::SigBit>() const { return bits(); }
const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; }
operator std::vector<RTLIL::SigChunk>() const;
operator std::vector<RTLIL::SigBit>() const { return to_sigbit_vector(); }
const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < size() ? (*this)[offset] : defval; }
[[nodiscard]] Hasher hash_into(Hasher h) const { if (!hash_) updhash(); h.eat(hash_); return h; }
[[nodiscard]] Hasher hash_into(Hasher h) const {
Hasher::hash_t val;
if (std::optional<Hasher::hash_t> current = hash_.read())
val = *current;
else
val = updhash();
h.eat(val);
return h;
}
#ifndef NDEBUG
void check(Module *mod = nullptr) const;
@ -2314,13 +2491,15 @@ 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*() {
bit = (*sig_p)[index];
return bit;
}
inline RTLIL::SigBit::SigBit(const RTLIL::SigSpec &sig) {
log_assert(sig.size() == 1 && sig.chunks().size() == 1);
*this = SigBit(sig.chunks().front());
log_assert(sig.size() == 1);
auto it = sig.chunks().begin();
*this = SigBit(*it);
}
template<typename T>

View File

@ -277,14 +277,26 @@ inline int ceil_log2(int x)
#endif
}
template <typename T>
auto reversed(T& container) {
struct reverse_view {
reverse_view(T& container) : container(container) {}
auto begin() const { return container.rbegin(); }
auto end() const { return container.rend(); }
T& container;
};
return reverse_view{container};
}
template <typename T>
auto reversed(const T& container) {
struct reverse_view {
const T& cont;
auto begin() const { return cont.rbegin(); }
auto end() const { return cont.rend(); }
};
return reverse_view{container};
struct reverse_view {
reverse_view(const T& container) : container(container) {}
auto begin() const { return container.rbegin(); }
auto end() const { return container.rend(); }
const T& container;
};
return reverse_view{container};
}
YOSYS_NAMESPACE_END

View File

@ -278,11 +278,12 @@ struct ShowWorker
std::vector<std::string> label_pieces;
int bitpos = sig.size()-1;
for (int rep, chunk_idx = ((int) sig.chunks().size()) - 1; chunk_idx >= 0; chunk_idx -= rep) {
const RTLIL::SigChunk &c = sig.chunks().at(chunk_idx);
RTLIL::SigSpec::Chunks sig_chunks = sig.chunks();
for (int rep, chunk_idx = ((int) sig_chunks.size()) - 1; chunk_idx >= 0; chunk_idx -= rep) {
const RTLIL::SigChunk &c = sig_chunks.at(chunk_idx);
// Find the number of times this chunk is repeating
for (rep = 1; chunk_idx - rep >= 0 && c == sig.chunks().at(chunk_idx - rep); rep++);
for (rep = 1; chunk_idx - rep >= 0 && c == sig_chunks.at(chunk_idx - rep); rep++);
int cl, cr;
cl = c.offset + c.width - 1;

View File

@ -1428,13 +1428,13 @@ void reintegrate(RTLIL::Module *module, bool dff_mode)
// Copy connections (and rename) from mapped_mod to module
for (auto conn : mapped_mod->connections()) {
if (!conn.first.is_fully_const()) {
auto chunks = conn.first.chunks();
std::vector<RTLIL::SigChunk> chunks = conn.first.chunks();
for (auto &c : chunks)
c.wire = module->wires_.at(remap_name(c.wire->name));
conn.first = std::move(chunks);
}
if (!conn.second.is_fully_const()) {
auto chunks = conn.second.chunks();
std::vector<RTLIL::SigChunk> chunks = conn.second.chunks();
for (auto &c : chunks)
if (c.wire)
c.wire = module->wires_.at(remap_name(c.wire->name));