Skip to content

Commit 76246c9

Browse files
committed
Implement SigSpec::updhash() using a relaxed atomic for thread-safety
1 parent 8a5fcae commit 76246c9

File tree

2 files changed

+66
-31
lines changed

2 files changed

+66
-31
lines changed

kernel/rtlil.cc

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4684,17 +4684,12 @@ void RTLIL::SigSpec::unpack()
46844684
new (&bits_) std::vector<RTLIL::SigBit>(std::move(bits));
46854685
}
46864686

4687-
void RTLIL::SigSpec::updhash() const
4687+
Hasher::hash_t RTLIL::SigSpec::updhash() const
46884688
{
4689-
RTLIL::SigSpec *that = (RTLIL::SigSpec*)this;
4690-
4691-
if (that->hash_ != 0)
4692-
return;
4693-
46944689
cover("kernel.rtlil.sigspec.hash");
46954690

46964691
Hasher h;
4697-
for (auto &c : that->chunks())
4692+
for (auto &c : chunks())
46984693
if (c.wire == NULL) {
46994694
for (auto &v : c.data)
47004695
h.eat(v);
@@ -4703,17 +4698,19 @@ void RTLIL::SigSpec::updhash() const
47034698
h.eat(c.offset);
47044699
h.eat(c.width);
47054700
}
4706-
that->hash_ = h.yield();
4707-
if (that->hash_ == 0)
4708-
that->hash_ = 1;
4701+
Hasher::hash_t result = h.yield();
4702+
if (result == 0)
4703+
result = 1;
4704+
hash_.set(result);
4705+
return result;
47094706
}
47104707

47114708
void RTLIL::SigSpec::sort()
47124709
{
47134710
unpack();
47144711
cover("kernel.rtlil.sigspec.sort");
47154712
std::sort(bits_.begin(), bits_.end());
4716-
hash_ = 0;
4713+
hash_.clear();
47174714
}
47184715

47194716
void RTLIL::SigSpec::sort_and_unify()
@@ -4730,7 +4727,7 @@ void RTLIL::SigSpec::sort_and_unify()
47304727
unique_bits.erase(last, unique_bits.end());
47314728

47324729
*this = unique_bits;
4733-
hash_ = 0;
4730+
hash_.clear();
47344731
}
47354732

47364733
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
48344831
if (other != NULL) {
48354832
log_assert(size() == other->size());
48364833
other->unpack();
4837-
other->hash_ = 0;
4834+
other->hash_.clear();
48384835
}
48394836

48404837
for (int i = GetSize(bits_) - 1; i >= 0; i--)
@@ -4851,7 +4848,7 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe
48514848
break;
48524849
}
48534850
}
4854-
hash_ = 0;
4851+
hash_.clear();
48554852

48564853
check();
48574854
}
@@ -4879,7 +4876,7 @@ void RTLIL::SigSpec::remove2(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec
48794876
if (other != NULL) {
48804877
log_assert(size() == other->size());
48814878
other->unpack();
4882-
other->hash_ = 0;
4879+
other->hash_.clear();
48834880
}
48844881

48854882
for (int i = GetSize(bits_) - 1; i >= 0; i--) {
@@ -4889,7 +4886,7 @@ void RTLIL::SigSpec::remove2(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec
48894886
other->bits_.erase(other->bits_.begin() + i);
48904887
}
48914888
}
4892-
hash_ = 0;
4889+
hash_.clear();
48934890

48944891
check();
48954892
}
@@ -4906,7 +4903,7 @@ void RTLIL::SigSpec::remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigS
49064903
if (other != NULL) {
49074904
log_assert(size() == other->size());
49084905
other->unpack();
4909-
other->hash_ = 0;
4906+
other->hash_.clear();
49104907
}
49114908

49124909
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
49164913
other->bits_.erase(other->bits_.begin() + i);
49174914
}
49184915
}
4919-
hash_ = 0;
4916+
hash_.clear();
49204917

49214918
check();
49224919
}
@@ -4933,7 +4930,7 @@ void RTLIL::SigSpec::remove2(const pool<RTLIL::Wire*> &pattern, RTLIL::SigSpec *
49334930
if (other != NULL) {
49344931
log_assert(size() == other->size());
49354932
other->unpack();
4936-
other->hash_ = 0;
4933+
other->hash_.clear();
49374934
}
49384935

49394936
for (int i = GetSize(bits_) - 1; i >= 0; i--) {
@@ -4943,7 +4940,7 @@ void RTLIL::SigSpec::remove2(const pool<RTLIL::Wire*> &pattern, RTLIL::SigSpec *
49434940
other->bits_.erase(other->bits_.begin() + i);
49444941
}
49454942
}
4946-
hash_ = 0;
4943+
hash_.clear();
49474944

49484945
check();
49494946
}
@@ -5031,7 +5028,7 @@ void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with)
50315028
bits_.at(offset + i) = bit;
50325029
++i;
50335030
}
5034-
hash_ = 0;
5031+
hash_.clear();
50355032

50365033
check();
50375034
}
@@ -5061,7 +5058,7 @@ void RTLIL::SigSpec::remove_const()
50615058
bits_.swap(new_bits);
50625059
}
50635060

5064-
hash_ = 0;
5061+
hash_.clear();
50655062
check();
50665063
}
50675064

@@ -5077,7 +5074,7 @@ void RTLIL::SigSpec::remove(int offset, int length)
50775074

50785075
bits_.erase(bits_.begin() + offset, bits_.begin() + offset + length);
50795076

5080-
hash_ = 0;
5077+
hash_.clear();
50815078
check();
50825079
}
50835080

@@ -5129,7 +5126,7 @@ void RTLIL::SigSpec::rewrite_wires(std::function<void(RTLIL::Wire*& wire)> rewri
51295126
new_bits.emplace_back(c, i);
51305127
}
51315128
bits_ = std::move(new_bits);
5132-
hash_ = 0;
5129+
hash_.clear();
51335130
}
51345131

51355132
void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal)
@@ -5144,7 +5141,7 @@ void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal)
51445141

51455142
cover("kernel.rtlil.sigspec.append");
51465143

5147-
hash_ = 0;
5144+
hash_.clear();
51485145
if (rep_ == CHUNK && signal.rep_ == CHUNK && chunk_.wire == signal.chunk_.wire) {
51495146
if (chunk_.wire == NULL) {
51505147
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)
51655162

51665163
void RTLIL::SigSpec::append(const RTLIL::SigBit &bit)
51675164
{
5168-
hash_ = 0;
5165+
hash_.clear();
51695166

51705167
if (size() == 0) {
51715168
destroy();

kernel/rtlil.h

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,9 +1238,39 @@ struct RTLIL::SigSpec
12381238
CHUNK,
12391239
BITS,
12401240
};
1241+
// An AtomicHash is either clear or a nonzero integer.
1242+
struct AtomicHash {
1243+
// Create an initially clear value.
1244+
AtomicHash() : atomic_(0) {}
1245+
AtomicHash(const AtomicHash &rhs) : atomic_(rhs.load()) {}
1246+
AtomicHash &operator=(const AtomicHash &rhs) { store(rhs.load()); return *this; }
1247+
// Read the hash. Returns nullopt if the hash is clear.
1248+
std::optional<Hasher::hash_t> read() const {
1249+
Hasher::hash_t value = load();
1250+
if (value == 0)
1251+
return std::nullopt;
1252+
return value;
1253+
}
1254+
// Set the hash. If the value is already set, then the new value must
1255+
// equal the current value.
1256+
void set(Hasher::hash_t value) const {
1257+
log_assert(value != 0);
1258+
Hasher::hash_t old = const_cast<std::atomic<Hasher::hash_t>&>(atomic_)
1259+
.exchange(value, std::memory_order_relaxed);
1260+
log_assert(old == 0 || old == value);
1261+
}
1262+
void clear() { store(0); }
1263+
private:
1264+
int load() const { return atomic_.load(std::memory_order_relaxed); }
1265+
void store(Hasher::hash_t value) const {
1266+
const_cast<std::atomic<Hasher::hash_t>&>(atomic_).store(value, std::memory_order_relaxed);
1267+
}
1268+
1269+
std::atomic<Hasher::hash_t> atomic_;
1270+
};
12411271

12421272
Representation rep_;
1243-
Hasher::hash_t hash_ = 0;
1273+
AtomicHash hash_;
12441274
union {
12451275
RTLIL::SigChunk chunk_;
12461276
std::vector<RTLIL::SigBit> bits_; // LSB at index 0
@@ -1257,7 +1287,7 @@ struct RTLIL::SigSpec
12571287
unpack();
12581288
}
12591289

1260-
void updhash() const;
1290+
Hasher::hash_t updhash() const;
12611291
void destroy() {
12621292
if (rep_ == CHUNK)
12631293
chunk_.~SigChunk();
@@ -1406,9 +1436,9 @@ struct RTLIL::SigSpec
14061436
inline const SigSpec &bits() const { return *this; }
14071437

14081438
inline int size() const { return rep_ == CHUNK ? chunk_.width : GetSize(bits_); }
1409-
inline bool empty() const { return size() == 0; }
1439+
inline bool empty() const { return size() == 0; };
14101440

1411-
inline RTLIL::SigBit &operator[](int index) { inline_unpack(); hash_ = 0; return bits_.at(index); }
1441+
inline RTLIL::SigBit &operator[](int index) { inline_unpack(); hash_.clear(); return bits_.at(index); }
14121442
inline RTLIL::SigBit operator[](int index) const {
14131443
if (rep_ == CHUNK) {
14141444
if (index < 0 || index >= chunk_.width)
@@ -1547,7 +1577,15 @@ struct RTLIL::SigSpec
15471577
operator std::vector<RTLIL::SigBit>() const { return to_sigbit_vector(); }
15481578
const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < size() ? (*this)[offset] : defval; }
15491579

1550-
[[nodiscard]] Hasher hash_into(Hasher h) const { if (!hash_) updhash(); h.eat(hash_); return h; }
1580+
[[nodiscard]] Hasher hash_into(Hasher h) const {
1581+
Hasher::hash_t val;
1582+
if (std::optional<Hasher::hash_t> current = hash_.read())
1583+
val = *current;
1584+
else
1585+
val = updhash();
1586+
h.eat(val);
1587+
return h;
1588+
}
15511589

15521590
#ifndef NDEBUG
15531591
void check(Module *mod = nullptr) const;

0 commit comments

Comments
 (0)