3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-04-24 01:25:33 +00:00

hashlib: redo interface for flexibility

This commit is contained in:
Emil J. Tywoniak 2024-10-01 15:12:03 +02:00
parent 0ab9fccbf1
commit 68e40d8563
36 changed files with 461 additions and 357 deletions

View file

@ -30,7 +30,7 @@ struct BitPatternPool
int width;
struct bits_t {
std::vector<RTLIL::State> bitdata;
mutable unsigned int cached_hash;
mutable Hasher::hash_t cached_hash;
bits_t(int width = 0) : bitdata(width), cached_hash(0) { }
RTLIL::State &operator[](int index) {
return bitdata[index];
@ -39,14 +39,15 @@ struct BitPatternPool
return bitdata[index];
}
bool operator==(const bits_t &other) const {
if (hash() != other.hash())
if (run_hash(*this) != run_hash(other))
return false;
return bitdata == other.bitdata;
}
unsigned int hash() const {
Hasher hash_acc(Hasher h) const {
if (!cached_hash)
cached_hash = hash_ops<std::vector<RTLIL::State>>::hash(bitdata);
return cached_hash;
cached_hash = run_hash(bitdata);
h.acc(cached_hash);
return h;
}
};
pool<bits_t> database;

View file

@ -39,13 +39,13 @@ bool AigNode::operator==(const AigNode &other) const
return true;
}
unsigned int AigNode::hash() const
Hasher AigNode::hash_acc(Hasher h) const
{
unsigned int h = mkhash_init;
h = mkhash(portname.hash(), portbit);
h = mkhash(h, inverter);
h = mkhash(h, left_parent);
h = mkhash(h, right_parent);
h.acc(portname);
h.acc(portbit);
h.acc(inverter);
h.acc(left_parent);
h.acc(right_parent);
return h;
}
@ -54,9 +54,10 @@ bool Aig::operator==(const Aig &other) const
return name == other.name;
}
unsigned int Aig::hash() const
Hasher Aig::hash_acc(Hasher h) const
{
return hash_ops<std::string>::hash(name);
h.acc(name);
return h;
}
struct AigMaker

View file

@ -34,7 +34,7 @@ struct AigNode
AigNode();
bool operator==(const AigNode &other) const;
unsigned int hash() const;
Hasher hash_acc(Hasher h) const;
};
struct Aig
@ -44,7 +44,7 @@ struct Aig
Aig(Cell *cell);
bool operator==(const Aig &other) const;
unsigned int hash() const;
Hasher hash_acc(Hasher h) const;
};
YOSYS_NAMESPACE_END

View file

@ -74,9 +74,11 @@ struct DriveBitWire
return offset < other.offset;
}
unsigned int hash() const
Hasher hash_acc(Hasher h) const
{
return mkhash_add(wire->name.hash(), offset);
h.acc(wire->name);
h.acc(offset);
return h;
}
operator SigBit() const
@ -107,9 +109,12 @@ struct DriveBitPort
return offset < other.offset;
}
unsigned int hash() const
Hasher hash_acc(Hasher h) const
{
return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset);
h.acc(cell->name);
h.acc(port);
h.acc(offset);
return h;
}
};
@ -133,9 +138,11 @@ struct DriveBitMarker
return offset < other.offset;
}
unsigned int hash() const
Hasher hash_acc(Hasher h) const
{
return mkhash_add(marker, offset);
h.acc(marker);
h.acc(offset);
return h;
}
};
@ -171,9 +178,10 @@ public:
return multiple_ == other.multiple_;
}
unsigned int hash() const
Hasher hash_acc(Hasher h) const
{
return multiple_.hash();
h.acc(multiple_);
return h;
}
};
@ -362,31 +370,31 @@ public:
return *this;
}
unsigned int hash() const
Hasher hash_acc(Hasher h) const
{
unsigned int inner;
switch (type_)
{
case DriveType::NONE:
inner = 0;
h.acc(0);
break;
case DriveType::CONSTANT:
inner = constant_;
h.acc(constant_);
break;
case DriveType::WIRE:
inner = wire_.hash();
h.acc(wire_);
break;
case DriveType::PORT:
inner = port_.hash();
h.acc(port_);
break;
case DriveType::MARKER:
inner = marker_.hash();
h.acc(marker_);
break;
case DriveType::MULTIPLE:
inner = multiple_.hash();
h.acc(multiple_);
break;
}
return mkhash((unsigned int)type_, inner);
h.acc(type_);
return h;
}
bool operator==(const DriveBit &other) const
@ -508,9 +516,12 @@ struct DriveChunkWire
return offset < other.offset;
}
unsigned int hash() const
Hasher hash_acc(Hasher h) const
{
return mkhash_add(mkhash(wire->name.hash(), width), offset);
h.acc(wire->name);
h.acc(width);
h.acc(offset);
return h;
}
explicit operator SigChunk() const
@ -569,9 +580,13 @@ struct DriveChunkPort
return offset < other.offset;
}
unsigned int hash() const
Hasher hash_acc(Hasher h) const
{
return mkhash_add(mkhash(mkhash(cell->name.hash(), port.hash()), width), offset);
h.acc(cell->name);
h.acc(port);
h.acc(width);
h.acc(offset);
return h;
}
};
@ -613,9 +628,12 @@ struct DriveChunkMarker
return offset < other.offset;
}
unsigned int hash() const
Hasher hash_acc(Hasher h) const
{
return mkhash_add(mkhash(marker, width), offset);
h.acc(marker);
h.acc(width);
h.acc(offset);
return h;
}
};
@ -656,9 +674,11 @@ public:
return false; // TODO implement, canonicalize order
}
unsigned int hash() const
Hasher hash_acc(Hasher h) const
{
return mkhash(width_, multiple_.hash());
h.acc(width_);
h.acc(multiple_);
return h;
}
};
@ -910,31 +930,31 @@ public:
bool try_append(DriveBit const &bit);
bool try_append(DriveChunk const &chunk);
unsigned int hash() const
Hasher hash_acc(Hasher h) const
{
unsigned int inner;
switch (type_)
{
case DriveType::NONE:
inner = 0;
h.acc(0);
break;
case DriveType::CONSTANT:
inner = constant_.hash();
h.acc(constant_);
break;
case DriveType::WIRE:
inner = wire_.hash();
h.acc(wire_);
break;
case DriveType::PORT:
inner = port_.hash();
h.acc(port_);
break;
case DriveType::MARKER:
inner = marker_.hash();
h.acc(marker_);
break;
case DriveType::MULTIPLE:
inner = multiple_.hash();
h.acc(multiple_);
break;
}
return mkhash((unsigned int)type_, inner);
h.acc(type_);
return h;
}
bool operator==(const DriveChunk &other) const
@ -1138,17 +1158,25 @@ public:
DriveSpec &operator=(DriveBitMarker const &bit) { return *this = DriveBit(bit); }
DriveSpec &operator=(DriveBitMultiple const &bit) { return *this = DriveBit(bit); }
unsigned int hash() const {
if (hash_ != 0) return hash_;
void updhash() const {
DriveSpec *that = (DriveSpec*)this;
pack();
hash_ = hash_ops<std::vector<DriveChunk>>().hash(chunks_);
hash_ |= (hash_ == 0);
return hash_;
that->hash_ = run_hash(chunks_);
that->hash_ |= (that->hash_ == 0);
}
Hasher hash_acc(Hasher h) const {
if (hash_ == 0)
updhash();
h.acc(hash_);
return h;
}
bool operator==(DriveSpec const &other) const {
if (size() != other.size() || hash() != other.hash())
updhash();
other.updhash();
if (size() != other.size() || hash_ != other.hash_)
return false;
return chunks() == other.chunks();
}
@ -1181,7 +1209,8 @@ private:
bool operator==(const DriveBitId &other) const { return id == other.id; }
bool operator!=(const DriveBitId &other) const { return id != other.id; }
bool operator<(const DriveBitId &other) const { return id < other.id; }
unsigned int hash() const { return id; }
// unsigned int hash() const { return id; }
Hasher hash_acc(Hasher h) const { h.acc(id); return h; }
};
// Essentially a dict<DriveBitId, pool<DriveBitId>> but using less memory
// and fewer allocations

View file

@ -151,7 +151,7 @@ namespace Functional {
// returns the data width of a bitvector sort, errors out for other sorts
int data_width() const { return std::get<1>(_v).second; }
bool operator==(Sort const& other) const { return _v == other._v; }
unsigned int hash() const { return mkhash(_v); }
Hasher hash_acc(Hasher h) const { h.acc(_v); return h; }
};
class IR;
class Factory;
@ -225,8 +225,10 @@ namespace Functional {
const RTLIL::Const &as_const() const { return std::get<RTLIL::Const>(_extra); }
std::pair<IdString, IdString> as_idstring_pair() const { return std::get<std::pair<IdString, IdString>>(_extra); }
int as_int() const { return std::get<int>(_extra); }
int hash() const {
return mkhash((unsigned int) _fn, mkhash(_extra));
Hasher hash_acc(Hasher h) const {
h.acc((unsigned int) _fn);
h.acc(_extra);
return h;
}
bool operator==(NodeData const &other) const {
return _fn == other._fn && _extra == other._extra;

View file

@ -16,27 +16,47 @@
#include <algorithm>
#include <string>
#include <vector>
#include <type_traits>
#include <stdint.h>
namespace hashlib {
/**
* HASHING
*
* The Hasher knows how to hash 32 and 64-bit integers. That's it.
* In the future, it could be expanded to do vectors with SIMD.
*
* The Hasher doesn't know how to hash common standard containers
* and compositions. However, hashlib provides centralized wrappers.
*
* Hashlib doesn't know how to hash silly Yosys-specific types.
* Hashlib doesn't depend on Yosys and can be used standalone.
* Please don't use hashlib standalone for new projects.
*
* The hash_ops type is now always left to its default value, derived
* from templated functions through SFINAE. Providing custom ops is
* still supported.
*
* HASH TABLES
*
* We implement associative data structures with separate chaining.
* Linked lists use integers into the indirection hashtable array
* instead of pointers.
*/
// TODO describe how comparison hashes are special
// TODO draw the line between generic and hash function specific code
const int hashtable_size_trigger = 2;
const int hashtable_size_factor = 3;
// The XOR version of DJB2
inline unsigned int mkhash(unsigned int a, unsigned int b) {
return ((a << 5) + a) ^ b;
}
#define DJB2_BROKEN_SIZE
// traditionally 5381 is used as starting value for the djb2 hash
const unsigned int mkhash_init = 5381;
#ifdef DJB2_BROKEN_SIZE
// The ADD version of DJB2
// (use this version for cache locality in b)
inline unsigned int mkhash_add(unsigned int a, unsigned int b) {
return ((a << 5) + a) + b;
}
template<typename T>
struct hash_ops;
inline unsigned int mkhash_xorshift(unsigned int a) {
if (sizeof(a) == 4) {
@ -52,62 +72,76 @@ inline unsigned int mkhash_xorshift(unsigned int a) {
return a;
}
template<typename T> struct hash_ops {
class Hasher {
public: //TODO
using hash_t = uint32_t;
Hasher() {
// traditionally 5381 is used as starting value for the djb2 hash
state = 5381;
}
private:
uint32_t state;
// The XOR version of DJB2
[[nodiscard]]
static uint32_t mkhash(uint32_t a, uint32_t b) {
return ((a << 5) + a) ^ b;
}
public:
void hash32(uint32_t i) {
state = mkhash(i, state);
return;
}
void hash64(uint64_t i) {
state = mkhash((uint32_t)(i % (1ULL << 32ULL)), state);
state = mkhash((uint32_t)(i >> 32ULL), state);
return;
}
hash_t yield() {
return (hash_t)state;
}
template<typename T>
void acc(T t) {
*this = hash_ops<T>::hash_acc(t, *this);
}
void commutative_acc(uint32_t t) {
state ^= t;
}
};
#endif
template<typename T>
struct hash_ops {
static inline bool cmp(const T &a, const T &b) {
return a == b;
}
static inline unsigned int hash(const T &a) {
return a.hash();
}
};
struct hash_int_ops {
template<typename T>
static inline bool cmp(T a, T b) {
return a == b;
}
};
template<> struct hash_ops<bool> : hash_int_ops
{
static inline unsigned int hash(bool a) {
return a ? 1 : 0;
}
};
template<> struct hash_ops<int32_t> : hash_int_ops
{
static inline unsigned int hash(int32_t a) {
return a;
}
};
template<> struct hash_ops<int64_t> : hash_int_ops
{
static inline unsigned int hash(int64_t a) {
return mkhash((unsigned int)(a), (unsigned int)(a >> 32));
}
};
template<> struct hash_ops<uint32_t> : hash_int_ops
{
static inline unsigned int hash(uint32_t a) {
return a;
}
};
template<> struct hash_ops<uint64_t> : hash_int_ops
{
static inline unsigned int hash(uint64_t a) {
return mkhash((unsigned int)(a), (unsigned int)(a >> 32));
}
};
template<> struct hash_ops<std::string> {
static inline bool cmp(const std::string &a, const std::string &b) {
return a == b;
}
static inline unsigned int hash(const std::string &a) {
unsigned int v = 0;
for (auto c : a)
v = mkhash(v, c);
return v;
static inline Hasher hash_acc(const T &a, Hasher h) {
if constexpr (std::is_same_v<T, bool>) {
h.hash32(a ? 1 : 0);
return h;
} else if constexpr (std::is_integral_v<T>) {
static_assert(sizeof(T) <= sizeof(uint64_t));
if (sizeof(T) == sizeof(uint64_t))
h.hash64(a);
else
h.hash32(a);
return h;
} else if constexpr (std::is_enum_v<T>) {
using u_type = std::underlying_type_t<T>;
return hash_ops<u_type>::hash_acc((u_type) a, h);
} else if constexpr (std::is_pointer_v<T>) {
return hash_ops<uintptr_t>::hash_acc((uintptr_t) a, h);
} else if constexpr (std::is_same_v<T, std::string>) {
for (auto c : a)
h.hash32(c);
return h;
} else {
return a.hash_acc(h);
}
}
};
@ -115,8 +149,10 @@ template<typename P, typename Q> struct hash_ops<std::pair<P, Q>> {
static inline bool cmp(std::pair<P, Q> a, std::pair<P, Q> b) {
return a == b;
}
static inline unsigned int hash(std::pair<P, Q> a) {
return mkhash(hash_ops<P>::hash(a.first), hash_ops<Q>::hash(a.second));
static inline Hasher hash_acc(std::pair<P, Q> a, Hasher h) {
h = hash_ops<P>::hash_acc(a.first, h);
h = hash_ops<Q>::hash_acc(a.second, h);
return h;
}
};
@ -125,13 +161,15 @@ template<typename... T> struct hash_ops<std::tuple<T...>> {
return a == b;
}
template<size_t I = 0>
static inline typename std::enable_if<I == sizeof...(T), unsigned int>::type hash(std::tuple<T...>) {
return mkhash_init;
static inline typename std::enable_if<I == sizeof...(T), Hasher>::type hash_acc(std::tuple<T...>, Hasher h) {
return h;
}
template<size_t I = 0>
static inline typename std::enable_if<I != sizeof...(T), unsigned int>::type hash(std::tuple<T...> a) {
static inline typename std::enable_if<I != sizeof...(T), Hasher>::type hash_acc(std::tuple<T...> a, Hasher h) {
typedef hash_ops<typename std::tuple_element<I, std::tuple<T...>>::type> element_ops_t;
return mkhash(hash<I+1>(a), element_ops_t::hash(std::get<I>(a)));
h = hash_acc<I+1>(a, h);
h = element_ops_t::hash_acc(std::get<I>(a), h);
return h;
}
};
@ -139,10 +177,10 @@ template<typename T> struct hash_ops<std::vector<T>> {
static inline bool cmp(std::vector<T> a, std::vector<T> b) {
return a == b;
}
static inline unsigned int hash(std::vector<T> a) {
unsigned int h = mkhash_init;
static inline Hasher hash_acc(std::vector<T> a, Hasher h) {
h.acc(a.size());
for (auto k : a)
h = mkhash(h, hash_ops<T>::hash(k));
h.acc(k);
return h;
}
};
@ -154,20 +192,21 @@ struct hash_cstr_ops {
return false;
return true;
}
static inline unsigned int hash(const char *a) {
unsigned int hash = mkhash_init;
static inline Hasher hash_acc(const char *a, Hasher h) {
while (*a)
hash = mkhash(hash, *(a++));
return hash;
h.hash32(*(a++));
return h;
}
};
template <> struct hash_ops<char*> : hash_cstr_ops {};
struct hash_ptr_ops {
static inline bool cmp(const void *a, const void *b) {
return a == b;
}
static inline unsigned int hash(const void *a) {
return (uintptr_t)a;
static inline Hasher hash_acc(const void *a, Hasher h) {
return hash_ops<uintptr_t>::hash_acc((uintptr_t)a, h);
}
};
@ -176,22 +215,36 @@ struct hash_obj_ops {
return a == b;
}
template<typename T>
static inline unsigned int hash(const T *a) {
return a ? a->hash() : 0;
static inline Hasher hash_acc(const T *a, Hasher h) {
return a ? a->hash_acc(h) : h;
}
};
/**
* If you find yourself using this function, think hard
* about if it's the right thing to do. Mixing finalized
* hashes together with XORs or worse can destroy
* desirable qualities of the hash function
*/
template<typename T>
inline unsigned int mkhash(const T &v) {
return hash_ops<T>().hash(v);
Hasher::hash_t run_hash(const T& obj) {
Hasher h;
h.acc(obj);
return h.yield();
}
// #ifdef OTHER_HASH...
// [[deprecated]]
// inline unsigned int mkhash_add(unsigned int a, unsigned int b) {
// return mkhash(a, b);
// }
template<> struct hash_ops<std::monostate> {
static inline bool cmp(std::monostate a, std::monostate b) {
return a == b;
}
static inline unsigned int hash(std::monostate) {
return mkhash_init;
static inline Hasher hash_acc(std::monostate, Hasher h) {
return h;
}
};
@ -199,9 +252,10 @@ template<typename... T> struct hash_ops<std::variant<T...>> {
static inline bool cmp(std::variant<T...> a, std::variant<T...> b) {
return a == b;
}
static inline unsigned int hash(std::variant<T...> a) {
unsigned int h = std::visit([](const auto &v) { return mkhash(v); }, a);
return mkhash(a.index(), h);
static inline Hasher hash_acc(std::variant<T...> a, Hasher h) {
std::visit([& h](const auto &v) { h.acc(v); }, a);
h.acc(a.index());
return h;
}
};
@ -209,11 +263,12 @@ template<typename T> struct hash_ops<std::optional<T>> {
static inline bool cmp(std::optional<T> a, std::optional<T> b) {
return a == b;
}
static inline unsigned int hash(std::optional<T> a) {
static inline Hasher hash_acc(std::optional<T> a, Hasher h) {
if(a.has_value())
return mkhash(*a);
h.acc(*a);
else
return 0;
h.acc(0);
return h;
}
};
@ -245,14 +300,13 @@ inline int hashtable_size(int min_size)
throw std::length_error("hash table exceeded maximum size.");
}
template<typename K, typename T, typename OPS = hash_ops<K>> class dict;
template<typename K, int offset = 0, typename OPS = hash_ops<K>> class idict;
template<typename K, typename OPS = hash_ops<K>> class pool;
template<typename K, typename OPS = hash_ops<K>> class mfp;
template<typename K, typename T> class dict;
template<typename K, int offset = 0> class idict;
template<typename K> class pool;
template<typename K> class mfp;
template<typename K, typename T, typename OPS>
class dict
{
template<typename K, typename T>
class dict {
struct entry_t
{
std::pair<K, T> udata;
@ -266,7 +320,7 @@ class dict
std::vector<int> hashtable;
std::vector<entry_t> entries;
OPS ops;
hash_ops<K> ops;
#ifdef NDEBUG
static inline void do_assert(bool) { }
@ -278,9 +332,9 @@ class dict
int do_hash(const K &key) const
{
unsigned int hash = 0;
Hasher::hash_t hash = 0;
if (!hashtable.empty())
hash = ops.hash(key) % (unsigned int)(hashtable.size());
hash = run_hash<K>(key) % (unsigned int)(hashtable.size());
return hash;
}
@ -682,11 +736,13 @@ public:
return !operator==(other);
}
unsigned int hash() const {
unsigned int h = mkhash_init;
for (auto &entry : entries) {
h ^= hash_ops<K>::hash(entry.udata.first);
h ^= hash_ops<T>::hash(entry.udata.second);
Hasher hash_acc(Hasher h) const {
h.acc(entries.size());
for (auto &it : entries) {
Hasher entry_hash;
entry_hash.acc(it.udata.first);
entry_hash.acc(it.udata.second);
h.commutative_acc(entry_hash.yield());
}
return h;
}
@ -705,10 +761,10 @@ public:
const_iterator end() const { return const_iterator(nullptr, -1); }
};
template<typename K, typename OPS>
template<typename K>
class pool
{
template<typename, int, typename> friend class idict;
template<typename, int> friend class idict;
protected:
struct entry_t
@ -723,7 +779,7 @@ protected:
std::vector<int> hashtable;
std::vector<entry_t> entries;
OPS ops;
hash_ops<K> ops;
#ifdef NDEBUG
static inline void do_assert(bool) { }
@ -735,9 +791,9 @@ protected:
int do_hash(const K &key) const
{
unsigned int hash = 0;
Hasher::hash_t hash = 0;
if (!hashtable.empty())
hash = ops.hash(key) % (unsigned int)(hashtable.size());
hash = run_hash<K>(key) % (unsigned int)(hashtable.size());
return hash;
}
@ -1050,11 +1106,12 @@ public:
return !operator==(other);
}
unsigned int hash() const {
unsigned int hashval = mkhash_init;
for (auto &it : entries)
hashval ^= ops.hash(it.udata);
return hashval;
Hasher hash_acc(Hasher h) const {
h.acc(entries.size());
for (auto &it : entries) {
h.commutative_acc(run_hash(it.udata));
}
return h;
}
void reserve(size_t n) { entries.reserve(n); }
@ -1071,10 +1128,10 @@ public:
const_iterator end() const { return const_iterator(nullptr, -1); }
};
template<typename K, int offset, typename OPS>
template<typename K, int offset>
class idict
{
pool<K, OPS> database;
pool<K> database;
public:
class const_iterator
@ -1168,14 +1225,14 @@ public:
* mfp stands for "merge, find, promote"
* i-prefixed methods operate on indices in parents
*/
template<typename K, typename OPS>
template<typename K>
class mfp
{
mutable idict<K, 0, OPS> database;
mutable idict<K, 0> database;
mutable std::vector<int> parents;
public:
typedef typename idict<K, 0, OPS>::const_iterator const_iterator;
typedef typename idict<K, 0>::const_iterator const_iterator;
constexpr mfp()
{

View file

@ -363,13 +363,13 @@ void log_dump_val_worker(RTLIL::IdString v);
void log_dump_val_worker(RTLIL::SigSpec v);
void log_dump_val_worker(RTLIL::State v);
template<typename K, typename T, typename OPS> static inline void log_dump_val_worker(dict<K, T, OPS> &v);
template<typename K, typename OPS> static inline void log_dump_val_worker(pool<K, OPS> &v);
template<typename K, typename T> static inline void log_dump_val_worker(dict<K, T> &v);
template<typename K> static inline void log_dump_val_worker(pool<K> &v);
template<typename K> static inline void log_dump_val_worker(std::vector<K> &v);
template<typename T> static inline void log_dump_val_worker(T *ptr);
template<typename K, typename T, typename OPS>
static inline void log_dump_val_worker(dict<K, T, OPS> &v) {
template<typename K, typename T>
static inline void log_dump_val_worker(dict<K, T> &v) {
log("{");
bool first = true;
for (auto &it : v) {
@ -382,8 +382,8 @@ static inline void log_dump_val_worker(dict<K, T, OPS> &v) {
log(" }");
}
template<typename K, typename OPS>
static inline void log_dump_val_worker(pool<K, OPS> &v) {
template<typename K>
static inline void log_dump_val_worker(pool<K> &v) {
log("{");
bool first = true;
for (auto &it : v) {

View file

@ -48,8 +48,11 @@ struct ModIndex : public RTLIL::Monitor
return cell == other.cell && port == other.port && offset == other.offset;
}
unsigned int hash() const {
return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset);
Hasher hash_acc(Hasher h) const {
h.acc(cell->name);
h.acc(port);
h.acc(offset);
return h;
}
};
@ -57,6 +60,8 @@ struct ModIndex : public RTLIL::Monitor
{
bool is_input, is_output;
pool<PortInfo> ports;
// SigBitInfo() : SigBitInfo{} {}
// SigBitInfo& operator=(const SigBitInfo&) = default;
SigBitInfo() : is_input(false), is_output(false) { }
@ -304,6 +309,8 @@ struct ModWalker
RTLIL::Cell *cell;
RTLIL::IdString port;
int offset;
PortBit(Cell* c, IdString p, int o) : cell(c), port(p), offset(o) {}
// PortBit& operator=(const PortBit&) = default;
bool operator<(const PortBit &other) const {
if (cell != other.cell)
@ -317,8 +324,11 @@ struct ModWalker
return cell == other.cell && port == other.port && offset == other.offset;
}
unsigned int hash() const {
return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset);
Hasher hash_acc(Hasher h) const {
h.acc(cell->name);
h.acc(port);
h.acc(offset);
return h;
}
};
@ -355,7 +365,7 @@ struct ModWalker
{
for (int i = 0; i < int(bits.size()); i++)
if (bits[i].wire != NULL) {
PortBit pbit = { cell, port, i };
PortBit pbit {cell, port, i};
if (is_output) {
signal_drivers[bits[i]].insert(pbit);
cell_outputs[cell].insert(bits[i]);

View file

@ -34,7 +34,7 @@ YOSYS_NAMESPACE_BEGIN
bool RTLIL::IdString::destruct_guard_ok = false;
RTLIL::IdString::destruct_guard_t RTLIL::IdString::destruct_guard;
std::vector<char*> RTLIL::IdString::global_id_storage_;
dict<char*, int, hash_cstr_ops> RTLIL::IdString::global_id_index_;
dict<char*, int> RTLIL::IdString::global_id_index_;
#ifndef YOSYS_NO_IDS_REFCNT
std::vector<int> RTLIL::IdString::global_refcount_storage_;
std::vector<int> RTLIL::IdString::global_free_idx_list_;
@ -4230,17 +4230,17 @@ void RTLIL::SigSpec::updhash() const
cover("kernel.rtlil.sigspec.hash");
that->pack();
that->hash_ = mkhash_init;
Hasher h;
for (auto &c : that->chunks_)
if (c.wire == NULL) {
for (auto &v : c.data)
that->hash_ = mkhash(that->hash_, v);
h.acc(v);
} else {
that->hash_ = mkhash(that->hash_, c.wire->name.index_);
that->hash_ = mkhash(that->hash_, c.offset);
that->hash_ = mkhash(that->hash_, c.width);
h.acc(c.wire->name.index_);
h.acc(c.offset);
h.acc(c.width);
}
that->hash_ = h.yield();
if (that->hash_ == 0)
that->hash_ = 1;
}

View file

@ -93,7 +93,7 @@ namespace RTLIL
} destruct_guard;
static std::vector<char*> global_id_storage_;
static dict<char*, int, hash_cstr_ops> global_id_index_;
static dict<char*, int> global_id_index_;
#ifndef YOSYS_NO_IDS_REFCNT
static std::vector<int> global_refcount_storage_;
static std::vector<int> global_free_idx_list_;
@ -358,8 +358,8 @@ namespace RTLIL
*this = IdString();
}
unsigned int hash() const {
return index_;
Hasher hash_acc(Hasher h) const {
return hash_ops<int>::hash_acc(index_, h);
}
// The following is a helper key_compare class. Instead of for example std::set<Cell*>
@ -711,10 +711,10 @@ struct RTLIL::Const
bits.resize(width, bits.empty() ? RTLIL::State::Sx : bits.back());
}
inline unsigned int hash() const {
unsigned int h = mkhash_init;
inline Hasher hash_acc(Hasher h) const {
// TODO hash size
for (auto b : bits)
h = mkhash(h, b);
h.acc(b);
return h;
}
};
@ -803,7 +803,7 @@ struct RTLIL::SigBit
bool operator <(const RTLIL::SigBit &other) const;
bool operator ==(const RTLIL::SigBit &other) const;
bool operator !=(const RTLIL::SigBit &other) const;
unsigned int hash() const;
Hasher hash_acc(Hasher h) const;
};
struct RTLIL::SigSpecIterator
@ -844,7 +844,7 @@ struct RTLIL::SigSpec
{
private:
int width_;
unsigned long hash_;
Hasher::hash_t hash_;
std::vector<RTLIL::SigChunk> chunks_; // LSB at index 0
std::vector<RTLIL::SigBit> bits_; // LSB at index 0
@ -885,9 +885,10 @@ public:
SigSpec(const std::set<RTLIL::SigBit> &bits);
explicit SigSpec(bool bit);
[[deprecated]]
size_t get_hash() const {
if (!hash_) hash();
return hash_;
log_assert(false && "deprecated");
return 0;
}
inline const std::vector<RTLIL::SigChunk> &chunks() const { pack(); return chunks_; }
@ -996,7 +997,7 @@ public:
operator std::vector<RTLIL::SigBit>() const { return bits(); }
const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; }
unsigned int hash() const { if (!hash_) updhash(); return hash_; };
Hasher hash_acc(Hasher h) const { if (!hash_) updhash(); h.acc(hash_); return h; }
#ifndef NDEBUG
void check(Module *mod = nullptr) const;
@ -1037,8 +1038,8 @@ struct RTLIL::Selection
struct RTLIL::Monitor
{
unsigned int hashidx_;
unsigned int hash() const { return hashidx_; }
Hasher::hash_t hashidx_;
Hasher hash_acc(Hasher h) const { h.acc(hashidx_); return h; }
Monitor() {
static unsigned int hashidx_count = 123456789;
@ -1060,8 +1061,8 @@ struct define_map_t;
struct RTLIL::Design
{
unsigned int hashidx_;
unsigned int hash() const { return hashidx_; }
Hasher::hash_t hashidx_;
Hasher hash_acc(Hasher h) const { h.acc(hashidx_); return h; }
pool<RTLIL::Monitor*> monitors;
dict<std::string, std::string> scratchpad;
@ -1165,8 +1166,8 @@ struct RTLIL::Design
struct RTLIL::Module : public RTLIL::AttrObject
{
unsigned int hashidx_;
unsigned int hash() const { return hashidx_; }
Hasher::hash_t hashidx_;
Hasher hash_acc(Hasher h) const { h.acc(hashidx_); return h; }
protected:
void add(RTLIL::Wire *wire);
@ -1516,8 +1517,8 @@ void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire);
struct RTLIL::Wire : public RTLIL::AttrObject
{
unsigned int hashidx_;
unsigned int hash() const { return hashidx_; }
Hasher::hash_t hashidx_;
Hasher hash_acc(Hasher h) const { h.acc(hashidx_); return h; }
protected:
// use module->addWire() and module->remove() to create or destroy wires
@ -1555,8 +1556,8 @@ inline int GetSize(RTLIL::Wire *wire) {
struct RTLIL::Memory : public RTLIL::AttrObject
{
unsigned int hashidx_;
unsigned int hash() const { return hashidx_; }
Hasher::hash_t hashidx_;
Hasher hash_acc(Hasher h) const { h.acc(hashidx_); return h; }
Memory();
@ -1570,8 +1571,8 @@ struct RTLIL::Memory : public RTLIL::AttrObject
struct RTLIL::Cell : public RTLIL::AttrObject
{
unsigned int hashidx_;
unsigned int hash() const { return hashidx_; }
Hasher::hash_t hashidx_;
Hasher hash_acc(Hasher h) const { h.acc(hashidx_); return h; }
protected:
// use module->addCell() and module->remove() to create or destroy cells
@ -1680,8 +1681,8 @@ struct RTLIL::SyncRule
struct RTLIL::Process : public RTLIL::AttrObject
{
unsigned int hashidx_;
unsigned int hash() const { return hashidx_; }
Hasher::hash_t hashidx_;
Hasher hash_acc(Hasher h) const { h.acc(hashidx_); return h; }
protected:
// use module->addProcess() and module->remove() to create or destroy processes
@ -1725,10 +1726,14 @@ inline bool RTLIL::SigBit::operator!=(const RTLIL::SigBit &other) const {
return (wire != other.wire) || (wire ? (offset != other.offset) : (data != other.data));
}
inline unsigned int RTLIL::SigBit::hash() const {
if (wire)
return mkhash_add(wire->name.hash(), offset);
return data;
inline Hasher RTLIL::SigBit::hash_acc(Hasher h) const {
if (wire) {
h = wire->name.hash_acc(h);
h.acc(offset);
return h;
}
h.acc(data);
return h;
}
inline RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const {

View file

@ -318,7 +318,7 @@ struct ModuleItem {
Cell *cell() const { return type == Type::Cell ? static_cast<Cell *>(ptr) : nullptr; }
bool operator==(const ModuleItem &other) const { return ptr == other.ptr && type == other.type; }
unsigned int hash() const { return (uintptr_t)ptr; }
Hasher hash_acc(Hasher h) const { h.acc(ptr); return h; }
};
static inline void log_dump_val_worker(typename IdTree<ModuleItem>::Cursor cursor ) { log("%p %s", cursor.target, log_id(cursor.scope_name)); }

View file

@ -29,7 +29,11 @@ struct SigPool
struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
unsigned int hash() const { return first->name.hash() + second; }
Hasher hash_acc(Hasher h) const {
h.acc(first->name);
h.acc(second);
return h;
}
};
pool<bitDef_t> bits;
@ -143,7 +147,11 @@ struct SigSet
struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
unsigned int hash() const { return first->name.hash() + second; }
Hasher hash_acc(Hasher h) const {
h.acc(first->name);
h.acc(second);
return h;
}
};
dict<bitDef_t, std::set<T, Compare>> bits;

View file

@ -36,7 +36,11 @@ struct TimingInfo
explicit NameBit(const RTLIL::SigBit &b) : name(b.wire->name), offset(b.offset) {}
bool operator==(const NameBit& nb) const { return nb.name == name && nb.offset == offset; }
bool operator!=(const NameBit& nb) const { return !operator==(nb); }
unsigned int hash() const { return mkhash_add(name.hash(), offset); }
Hasher hash_acc(Hasher h) const {
h.acc(name);
h.acc(offset);
return h;
}
};
struct BitBit
{
@ -44,7 +48,11 @@ struct TimingInfo
BitBit(const NameBit &first, const NameBit &second) : first(first), second(second) {}
BitBit(const SigBit &first, const SigBit &second) : first(first), second(second) {}
bool operator==(const BitBit& bb) const { return bb.first == first && bb.second == second; }
unsigned int hash() const { return mkhash_add(first.hash(), second.hash()); }
Hasher hash_acc(Hasher h) const {
h.acc(first);
h.acc(second);
return h;
}
};
struct ModuleTiming

View file

@ -31,17 +31,17 @@ YOSYS_NAMESPACE_BEGIN
// A map-like container, but you can save and restore the state
// ------------------------------------------------
template<typename Key, typename T, typename OPS = hash_ops<Key>>
template<typename Key, typename T>
struct stackmap
{
private:
std::vector<dict<Key, T*, OPS>> backup_state;
dict<Key, T, OPS> current_state;
std::vector<dict<Key, T*>> backup_state;
dict<Key, T> current_state;
static T empty_tuple;
public:
stackmap() { }
stackmap(const dict<Key, T, OPS> &other) : current_state(other) { }
stackmap(const dict<Key, T> &other) : current_state(other) { }
template<typename Other>
void operator=(const Other &other)
@ -94,7 +94,7 @@ public:
current_state.erase(k);
}
const dict<Key, T, OPS> &stdmap()
const dict<Key, T> &stdmap()
{
return current_state;
}
@ -128,7 +128,7 @@ public:
// A simple class for topological sorting
// ------------------------------------------------
template <typename T, typename C = std::less<T>, typename OPS = hash_ops<T>> class TopoSort
template <typename T, typename C = std::less<T>> class TopoSort
{
public:
// We use this ordering of the edges in the adjacency matrix for

View file

@ -173,6 +173,15 @@ using std::get;
using std::min;
using std::max;
using hashlib::Hasher;
using hashlib::run_hash;
using hashlib::hash_ops;
using hashlib::mkhash_xorshift;
using hashlib::dict;
using hashlib::idict;
using hashlib::pool;
using hashlib::mfp;
// A primitive shared string implementation that does not
// move its .c_str() when the object is copied or moved.
struct shared_str {
@ -183,22 +192,12 @@ struct shared_str {
const char *c_str() const { return content->c_str(); }
const string &str() const { return *content; }
bool operator==(const shared_str &other) const { return *content == *other.content; }
unsigned int hash() const { return hashlib::hash_ops<std::string>::hash(*content); }
Hasher hash_acc(Hasher h) const {
h.acc(*content);
return h;
}
};
using hashlib::mkhash;
using hashlib::mkhash_init;
using hashlib::mkhash_add;
using hashlib::mkhash_xorshift;
using hashlib::hash_ops;
using hashlib::hash_cstr_ops;
using hashlib::hash_ptr_ops;
using hashlib::hash_obj_ops;
using hashlib::dict;
using hashlib::idict;
using hashlib::pool;
using hashlib::mfp;
namespace RTLIL {
struct IdString;
struct Const;
@ -237,26 +236,6 @@ using RTLIL::State;
using RTLIL::SigChunk;
using RTLIL::SigSig;
namespace hashlib {
template<> struct hash_ops<RTLIL::Wire*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Cell*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Memory*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Process*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Module*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Design*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Monitor*> : hash_obj_ops {};
template<> struct hash_ops<AST::AstNode*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Wire*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Cell*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Memory*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Process*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Module*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Design*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Monitor*> : hash_obj_ops {};
template<> struct hash_ops<const AST::AstNode*> : hash_obj_ops {};
}
void memhasher_on();
void memhasher_off();
void memhasher_do();
@ -367,10 +346,6 @@ RTLIL::IdString new_id_suffix(std::string file, int line, std::string func, std:
static const YOSYS_NAMESPACE_PREFIX RTLIL::IdString id(q); return id; })()
namespace ID = RTLIL::ID;
namespace hashlib {
template<> struct hash_ops<RTLIL::State> : hash_ops<int> {};
}
YOSYS_NAMESPACE_END

View file

@ -35,7 +35,7 @@ struct IdPath : public std::vector<RTLIL::IdString>
bool has_address() const { int tmp; return get_address(tmp); };
bool get_address(int &addr) const;
int hash() const { return hashlib::hash_ops<std::vector<RTLIL::IdString>>::hash(*this); }
Hasher hash_acc(Hasher h) const { h.acc(*this); return h; }
};
struct WitnessHierarchyItem {