Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Neater hashing interface #4524

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
hashlib: interface WIP
  • Loading branch information
widlarizer committed Sep 3, 2024
commit 0824ec9c051a4ac1c247031b6aca4318ae6a2b09
4 changes: 2 additions & 2 deletions frontends/ast/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,11 @@ namespace AST
std::string type2str(AstNodeType type);

// The AST is built using instances of this struct
struct AstNode
struct AstNode : public Hashable
{
// for dict<> and pool<>
unsigned int hashidx_;
unsigned int hash() const { return hashidx_; }
hash_t hash_acc(hash_t h) const final { return mkhash(h, hashidx_); }

// this nodes type
AstNodeType type;
Expand Down
8 changes: 4 additions & 4 deletions kernel/bitpattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@

YOSYS_NAMESPACE_BEGIN

struct BitPatternPool
struct BitPatternPool : public Hashable
{
int width;
struct bits_t {
std::vector<RTLIL::State> bitdata;
mutable unsigned int cached_hash;
mutable hash_t cached_hash;
bits_t(int width = 0) : bitdata(width), cached_hash(0) { }
RTLIL::State &operator[](int index) {
return bitdata[index];
Expand All @@ -43,10 +43,10 @@ struct BitPatternPool
return false;
return bitdata == other.bitdata;
}
unsigned int hash() const {
hash_t hash_acc(hash_t h) const final {
if (!cached_hash)
cached_hash = hash_ops<std::vector<RTLIL::State>>::hash(bitdata);
return cached_hash;
return mkhash(h, cached_hash);
}
};
pool<bits_t> database;
Expand Down
12 changes: 6 additions & 6 deletions kernel/cellaigs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ bool AigNode::operator==(const AigNode &other) const
return true;
}

unsigned int AigNode::hash() const
hash_t AigNode::hash_acc(hash_t 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 = portname.hash_acc(h);
h = mkhash(portbit, h);
h = mkhash(inverter, h);
h = mkhash(left_parent, h);
h = mkhash(right_parent, h);
return h;
}

Expand Down
4 changes: 2 additions & 2 deletions kernel/cellaigs.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

YOSYS_NAMESPACE_BEGIN

struct AigNode
struct AigNode : public Hashable
{
IdString portname;
int portbit;
Expand All @@ -34,7 +34,7 @@ struct AigNode

AigNode();
bool operator==(const AigNode &other) const;
unsigned int hash() const;
hash_t hash_acc(hash_t h) const final;
};

struct Aig
Expand Down
121 changes: 92 additions & 29 deletions kernel/hashlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,24 @@ inline unsigned int mkhash(unsigned int a, unsigned int b) {
// traditionally 5381 is used as starting value for the djb2 hash
const unsigned int mkhash_init = 5381;

// The ADD version of DJB2
// (use this version for cache locality in b)
// TODO ifdef this
typedef uint64_t hash_t;
// typedef hash_t acc_t;

struct Hashable {
virtual ~Hashable() = 0;
public:
[[nodiscard]]
virtual hash_t hash_acc(hash_t acc) const = 0;
[[nodiscard]]
hash_t hash() const {
return hash_acc(mkhash_init);
}
};

[[deprecated]]
inline unsigned int mkhash_add(unsigned int a, unsigned int b) {
return ((a << 5) + a) + b;
return mkhash(a, b);
}

inline unsigned int mkhash_xorshift(unsigned int a) {
Expand All @@ -52,11 +66,17 @@ inline unsigned int mkhash_xorshift(unsigned int a) {
return a;
}

template<typename T> struct hash_ops {


template<typename T, typename = void>
struct hash_ops: std::false_type {};

template<typename T>
struct hash_ops<T, std::enable_if_t<std::is_base_of_v<Hashable, T>>> {
static inline bool cmp(const T &a, const T &b) {
return a == b;
}
static inline unsigned int hash(const T &a) {
static inline hash_t hash(const T &a) {
return a.hash();
}
};
Expand All @@ -70,31 +90,31 @@ struct hash_int_ops {

template<> struct hash_ops<bool> : hash_int_ops
{
static inline unsigned int hash(bool a) {
static inline hash_t hash(bool a) {
return a ? 1 : 0;
}
};
template<> struct hash_ops<int32_t> : hash_int_ops
{
static inline unsigned int hash(int32_t a) {
static inline hash_t hash(int32_t a) {
return a;
}
};
template<> struct hash_ops<int64_t> : hash_int_ops
{
static inline unsigned int hash(int64_t a) {
static inline hash_t 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) {
static inline hash_t hash(uint32_t a) {
return a;
}
};
template<> struct hash_ops<uint64_t> : hash_int_ops
{
static inline unsigned int hash(uint64_t a) {
static inline hash_t hash(uint64_t a) {
return mkhash((unsigned int)(a), (unsigned int)(a >> 32));
}
};
Expand All @@ -103,7 +123,7 @@ 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) {
static inline hash_t hash(const std::string &a) {
unsigned int v = 0;
for (auto c : a)
v = mkhash(v, c);
Expand All @@ -115,7 +135,7 @@ 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) {
static inline hash_t hash(std::pair<P, Q> a) {
return mkhash(hash_ops<P>::hash(a.first), hash_ops<Q>::hash(a.second));
}
};
Expand All @@ -139,7 +159,7 @@ 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) {
static inline hash_t hash(std::vector<T> a) {
unsigned int h = mkhash_init;
for (auto k : a)
h = mkhash(h, hash_ops<T>::hash(k));
Expand All @@ -154,19 +174,21 @@ struct hash_cstr_ops {
return false;
return true;
}
static inline unsigned int hash(const char *a) {
unsigned int hash = mkhash_init;
static inline hash_t hash(const char *a) {
hash_t hash = mkhash_init;
while (*a)
hash = mkhash(hash, *(a++));
return hash;
}
};

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) {
static inline hash_t hash(const void *a) {
return (uintptr_t)a;
}
};
Expand All @@ -176,11 +198,53 @@ 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 hash_t hash(const T *a) {
return a ? a->hash_acc(mkhash_init) : 0;
}
};

// Primary template
template<typename T, typename = void>
struct is_hashable : std::false_type {};

// Helper to check if hash_ops<U> exists for a type U
template<typename U, typename = void>
struct has_hash_ops : std::false_type {};

template<typename U>
struct has_hash_ops<U, std::void_t<
decltype(hash_ops<U>::hash(std::declval<const U&>())),
decltype(hash_ops<U>::cmp(std::declval<const U&>(), std::declval<const U&>()))
>> : std::true_type {};

// Helper to check if T is convertible to U and U has hash_ops
template<typename T, typename U>
struct is_convertible_and_hashable :
std::conjunction<
std::is_convertible<T, U>,
has_hash_ops<U>
> {};

// Helper to check convertibility to a list of types
template<typename T, typename... Us>
struct is_convertible_to_any_hashable :
std::disjunction<
is_convertible_and_hashable<T, Us>...
> {};

// Specialization that checks for direct hash_ops or convertibility to hashable types
template<typename T>
struct is_hashable<T,
std::enable_if_t<
has_hash_ops<T>::value ||
is_convertible_to_any_hashable<T,
/* List your potential hashable types here */
int, char*, void*, /* Add more as needed */
std::string
>::value
>
> : std::true_type {};

template<typename T>
inline unsigned int mkhash(const T &v) {
return hash_ops<T>().hash(v);
Expand Down Expand Up @@ -220,8 +284,8 @@ 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, typename OPS>
class dict
{
class dict : public Hashable {
// static_assert(is_hashable<K>::value, "Key type must be derived from Hashable");
struct entry_t
{
std::pair<K, T> udata;
Expand All @@ -247,7 +311,7 @@ class dict

int do_hash(const K &key) const
{
unsigned int hash = 0;
hash_t hash = 0;
if (!hashtable.empty())
hash = ops.hash(key) % (unsigned int)(hashtable.size());
return hash;
Expand Down Expand Up @@ -651,8 +715,7 @@ class dict
return !operator==(other);
}

unsigned int hash() const {
unsigned int h = mkhash_init;
hash_t hash_acc(hash_t h) const final {
for (auto &entry : entries) {
h ^= hash_ops<K>::hash(entry.udata.first);
h ^= hash_ops<T>::hash(entry.udata.second);
Expand All @@ -675,8 +738,9 @@ class dict
};

template<typename K, typename OPS>
class pool
class pool : public Hashable
{
// static_assert(is_hashable<K>::value, "Key type must be derived from Hashable");
template<typename, int, typename> friend class idict;

protected:
Expand Down Expand Up @@ -704,7 +768,7 @@ class pool

int do_hash(const K &key) const
{
unsigned int hash = 0;
hash_t hash = 0;
if (!hashtable.empty())
hash = ops.hash(key) % (unsigned int)(hashtable.size());
return hash;
Expand Down Expand Up @@ -1019,11 +1083,10 @@ class pool
return !operator==(other);
}

unsigned int hash() const {
unsigned int hashval = mkhash_init;
hash_t hash_acc(hash_t h) const final {
for (auto &it : entries)
hashval ^= ops.hash(it.udata);
return hashval;
h ^= ops.hash(it.udata);
return h;
}

void reserve(size_t n) { entries.reserve(n); }
Expand Down
Loading