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

Implement SigSpec::updhash() using a relaxed atomic for thread-safety

This commit is contained in:
Robert O'Callahan 2025-10-31 10:48:39 +00:00
parent 45017e19ec
commit 0d3cd5d6c8
2 changed files with 66 additions and 31 deletions

View file

@ -4684,17 +4684,12 @@ void RTLIL::SigSpec::unpack()
new (&bits_) std::vector<RTLIL::SigBit>(std::move(bits)); new (&bits_) std::vector<RTLIL::SigBit>(std::move(bits));
} }
void RTLIL::SigSpec::updhash() const Hasher::hash_t RTLIL::SigSpec::updhash() const
{ {
RTLIL::SigSpec *that = (RTLIL::SigSpec*)this;
if (that->hash_ != 0)
return;
cover("kernel.rtlil.sigspec.hash"); cover("kernel.rtlil.sigspec.hash");
Hasher h; Hasher h;
for (auto &c : that->chunks()) for (auto &c : chunks())
if (c.wire == NULL) { if (c.wire == NULL) {
for (auto &v : c.data) for (auto &v : c.data)
h.eat(v); h.eat(v);
@ -4703,9 +4698,11 @@ void RTLIL::SigSpec::updhash() const
h.eat(c.offset); h.eat(c.offset);
h.eat(c.width); h.eat(c.width);
} }
that->hash_ = h.yield(); Hasher::hash_t result = h.yield();
if (that->hash_ == 0) if (result == 0)
that->hash_ = 1; result = 1;
hash_.set(result);
return result;
} }
void RTLIL::SigSpec::sort() void RTLIL::SigSpec::sort()
@ -4713,7 +4710,7 @@ void RTLIL::SigSpec::sort()
unpack(); unpack();
cover("kernel.rtlil.sigspec.sort"); cover("kernel.rtlil.sigspec.sort");
std::sort(bits_.begin(), bits_.end()); std::sort(bits_.begin(), bits_.end());
hash_ = 0; hash_.clear();
} }
void RTLIL::SigSpec::sort_and_unify() void RTLIL::SigSpec::sort_and_unify()
@ -4730,7 +4727,7 @@ void RTLIL::SigSpec::sort_and_unify()
unique_bits.erase(last, unique_bits.end()); unique_bits.erase(last, unique_bits.end());
*this = unique_bits; *this = unique_bits;
hash_ = 0; hash_.clear();
} }
void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with) void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with)
@ -4834,7 +4831,7 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe
if (other != NULL) { if (other != NULL) {
log_assert(size() == other->size()); log_assert(size() == other->size());
other->unpack(); other->unpack();
other->hash_ = 0; other->hash_.clear();
} }
for (int i = GetSize(bits_) - 1; i >= 0; i--) for (int i = GetSize(bits_) - 1; i >= 0; i--)
@ -4851,7 +4848,7 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe
break; break;
} }
} }
hash_ = 0; hash_.clear();
check(); check();
} }
@ -4879,7 +4876,7 @@ void RTLIL::SigSpec::remove2(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec
if (other != NULL) { if (other != NULL) {
log_assert(size() == other->size()); log_assert(size() == other->size());
other->unpack(); other->unpack();
other->hash_ = 0; other->hash_.clear();
} }
for (int i = GetSize(bits_) - 1; i >= 0; i--) { for (int i = GetSize(bits_) - 1; i >= 0; i--) {
@ -4889,7 +4886,7 @@ void RTLIL::SigSpec::remove2(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec
other->bits_.erase(other->bits_.begin() + i); other->bits_.erase(other->bits_.begin() + i);
} }
} }
hash_ = 0; hash_.clear();
check(); check();
} }
@ -4906,7 +4903,7 @@ void RTLIL::SigSpec::remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigS
if (other != NULL) { if (other != NULL) {
log_assert(size() == other->size()); log_assert(size() == other->size());
other->unpack(); other->unpack();
other->hash_ = 0; other->hash_.clear();
} }
for (int i = GetSize(bits_) - 1; i >= 0; i--) { for (int i = GetSize(bits_) - 1; i >= 0; i--) {
@ -4916,7 +4913,7 @@ void RTLIL::SigSpec::remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigS
other->bits_.erase(other->bits_.begin() + i); other->bits_.erase(other->bits_.begin() + i);
} }
} }
hash_ = 0; hash_.clear();
check(); check();
} }
@ -4933,7 +4930,7 @@ void RTLIL::SigSpec::remove2(const pool<RTLIL::Wire*> &pattern, RTLIL::SigSpec *
if (other != NULL) { if (other != NULL) {
log_assert(size() == other->size()); log_assert(size() == other->size());
other->unpack(); other->unpack();
other->hash_ = 0; other->hash_.clear();
} }
for (int i = GetSize(bits_) - 1; i >= 0; i--) { for (int i = GetSize(bits_) - 1; i >= 0; i--) {
@ -4943,7 +4940,7 @@ void RTLIL::SigSpec::remove2(const pool<RTLIL::Wire*> &pattern, RTLIL::SigSpec *
other->bits_.erase(other->bits_.begin() + i); other->bits_.erase(other->bits_.begin() + i);
} }
} }
hash_ = 0; hash_.clear();
check(); check();
} }
@ -5031,7 +5028,7 @@ void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with)
bits_.at(offset + i) = bit; bits_.at(offset + i) = bit;
++i; ++i;
} }
hash_ = 0; hash_.clear();
check(); check();
} }
@ -5061,7 +5058,7 @@ void RTLIL::SigSpec::remove_const()
bits_.swap(new_bits); bits_.swap(new_bits);
} }
hash_ = 0; hash_.clear();
check(); check();
} }
@ -5077,7 +5074,7 @@ void RTLIL::SigSpec::remove(int offset, int length)
bits_.erase(bits_.begin() + offset, bits_.begin() + offset + length); bits_.erase(bits_.begin() + offset, bits_.begin() + offset + length);
hash_ = 0; hash_.clear();
check(); check();
} }
@ -5129,7 +5126,7 @@ void RTLIL::SigSpec::rewrite_wires(std::function<void(RTLIL::Wire*& wire)> rewri
new_bits.emplace_back(c, i); new_bits.emplace_back(c, i);
} }
bits_ = std::move(new_bits); bits_ = std::move(new_bits);
hash_ = 0; hash_.clear();
} }
void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal)
@ -5144,7 +5141,7 @@ void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal)
cover("kernel.rtlil.sigspec.append"); cover("kernel.rtlil.sigspec.append");
hash_ = 0; hash_.clear();
if (rep_ == CHUNK && signal.rep_ == CHUNK && chunk_.wire == signal.chunk_.wire) { if (rep_ == CHUNK && signal.rep_ == CHUNK && chunk_.wire == signal.chunk_.wire) {
if (chunk_.wire == NULL) { if (chunk_.wire == NULL) {
chunk_.data.insert(chunk_.data.end(), signal.chunk_.data.begin(), signal.chunk_.data.end()); chunk_.data.insert(chunk_.data.end(), signal.chunk_.data.begin(), signal.chunk_.data.end());
@ -5165,7 +5162,7 @@ void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal)
void RTLIL::SigSpec::append(const RTLIL::SigBit &bit) void RTLIL::SigSpec::append(const RTLIL::SigBit &bit)
{ {
hash_ = 0; hash_.clear();
if (size() == 0) { if (size() == 0) {
destroy(); destroy();

View file

@ -1238,9 +1238,39 @@ private:
CHUNK, CHUNK,
BITS, 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);
}
std::atomic<Hasher::hash_t> atomic_;
};
Representation rep_; Representation rep_;
Hasher::hash_t hash_ = 0; AtomicHash hash_;
union { union {
RTLIL::SigChunk chunk_; RTLIL::SigChunk chunk_;
std::vector<RTLIL::SigBit> bits_; // LSB at index 0 std::vector<RTLIL::SigBit> bits_; // LSB at index 0
@ -1257,7 +1287,7 @@ private:
unpack(); unpack();
} }
void updhash() const; Hasher::hash_t updhash() const;
void destroy() { void destroy() {
if (rep_ == CHUNK) if (rep_ == CHUNK)
chunk_.~SigChunk(); chunk_.~SigChunk();
@ -1406,9 +1436,9 @@ public:
inline const SigSpec &bits() const { return *this; } inline const SigSpec &bits() const { return *this; }
inline int size() const { return rep_ == CHUNK ? chunk_.width : GetSize(bits_); } inline int size() const { return rep_ == CHUNK ? chunk_.width : GetSize(bits_); }
inline bool empty() const { return size() == 0; } inline bool empty() const { return size() == 0; };
inline RTLIL::SigBit &operator[](int index) { inline_unpack(); hash_ = 0; return bits_.at(index); } inline RTLIL::SigBit &operator[](int index) { inline_unpack(); hash_.clear(); return bits_.at(index); }
inline RTLIL::SigBit operator[](int index) const { inline RTLIL::SigBit operator[](int index) const {
if (rep_ == CHUNK) { if (rep_ == CHUNK) {
if (index < 0 || index >= chunk_.width) if (index < 0 || index >= chunk_.width)
@ -1547,7 +1577,15 @@ public:
operator std::vector<RTLIL::SigBit>() const { return to_sigbit_vector(); } 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; } 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 #ifndef NDEBUG
void check(Module *mod = nullptr) const; void check(Module *mod = nullptr) const;