From: Clifford Wolf Date: Sun, 28 Dec 2014 16:51:16 +0000 (+0100) Subject: Renamed hashmap.h to hashlib.h, some related improvements X-Git-Tag: yosys-0.5~204 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3da46d3437f076c27cef5121f26a1fa151dde1f6;p=yosys.git Renamed hashmap.h to hashlib.h, some related improvements --- diff --git a/kernel/hashlib.h b/kernel/hashlib.h new file mode 100644 index 000000000..a8d320865 --- /dev/null +++ b/kernel/hashlib.h @@ -0,0 +1,774 @@ +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. + +// ------------------------------------------------------- +// Written by Clifford Wolf in 2014 +// ------------------------------------------------------- + +#ifndef HASHLIB_H + +#include +#include +#include + +namespace hashlib { + +#define HASHLIB_SIZE_FACTOR 3 + +// The XOR version of DJB2 +// (traditionally 5381 is used as starting value for the djb2 hash) +inline unsigned int mkhash(unsigned int a, unsigned int b) { + return ((a << 5) + a) ^ b; +} + +// 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 struct hash_ops { + bool cmp(const T &a, const T &b) const { + return a == b; + } + unsigned int hash(const T &a) const { + return a.hash(); + } +}; + +template<> struct hash_ops { + template + bool cmp(T a, T b) const { + return a == b; + } + unsigned int hash(unsigned int a) const { + return a; + } +}; + +template<> struct hash_ops { + bool cmp(const std::string &a, const std::string &b) const { + return a == b; + } + unsigned int hash(const std::string &a) const { + unsigned int v = 0; + for (auto c : a) + v = mkhash(v, c); + return v; + } +}; + +struct hash_cstr_ops { + bool cmp(const char *a, const char *b) const { + for (int i = 0; a[i] || b[i]; i++) + if (a[i] != b[i]) + return false; + return true; + } + unsigned int hash(const char *a) const { + unsigned int hash = 5381; + while (*a) + hash = mkhash(hash, *(a++)); + return hash; + } +}; + +struct hash_ptr_ops { + bool cmp(const void *a, const void *b) const { + return a == b; + } + unsigned int hash(const void *a) const { + return (unsigned long)a; + } +}; + +struct hash_obj_ops { + bool cmp(const void *a, const void *b) const { + return a == b; + } + template + unsigned int hash(const T *a) const { + return a->hash(); + } +}; + +inline int hashtable_size(int old_size) +{ + // prime numbers, approx. in powers of two + if (old_size < 53) return 53; + if (old_size < 113) return 113; + if (old_size < 251) return 251; + if (old_size < 503) return 503; + if (old_size < 1129) return 1129; + if (old_size < 2503) return 2503; + if (old_size < 5023) return 5023; + if (old_size < 11299) return 11299; + if (old_size < 25097) return 25097; + if (old_size < 50291) return 50291; + if (old_size < 112997) return 112997; + if (old_size < 251003) return 251003; + if (old_size < 503003) return 503003; + if (old_size < 1129991) return 1129991; + if (old_size < 2509993) return 2509993; + if (old_size < 5029991) return 5029991; + if (old_size < 11299997) return 11299997; + if (old_size < 25099999) return 25099999; + if (old_size < 50299999) return 50299999; + if (old_size < 113000009) return 113000009; + if (old_size < 250999999) return 250999999; + if (old_size < 503000009) return 503000009; + if (old_size < 1129999999) return 1129999999; + throw std::length_error("hash table exceeded maximum size"); +} + +template> +class dict +{ + struct entry_t + { + int link; + std::pair udata; + + entry_t() : link(-1) { } + entry_t(const std::pair &udata) : link(1), udata(udata) { } + + bool is_free() const { return link < 0; } + int get_next() const { return (link > 0 ? link : -link) - 2; } + bool get_last() const { return get_next() == -1; } + void set_next_used(int next) { link = next + 2; } + void set_next_free(int next) { link = -(next + 2); } + }; + + std::vector hashtable; + std::vector entries; + int free_list, counter; + OPS ops; + + void init() + { + free_list = -1; + counter = 0; + } + + void init_from(const dict &other) + { + hashtable.clear(); + entries.clear(); + + counter = other.size(); + int new_size = hashtable_size(HASHLIB_SIZE_FACTOR * counter); + hashtable.resize(new_size); + new_size = new_size / HASHLIB_SIZE_FACTOR + 1; + entries.reserve(new_size); + + for (auto &it : other) + entries.push_back(entry_t(it)); + entries.resize(new_size); + rehash(); + } + + int mkhash(const K &key) const + { + unsigned int hash = 0; + if (!hashtable.empty()) + hash = ops.hash(key) % (unsigned int)(hashtable.size()); + return hash; + } + + void rehash() + { + free_list = -1; + + for (auto &h : hashtable) + h = -1; + + for (int i = 0; i < int(entries.size()); i++) + if (entries[i].is_free()) { + entries[i].set_next_free(free_list); + free_list = i; + } else { + int hash = mkhash(entries[i].udata.first); + entries[i].set_next_used(hashtable[hash]); + hashtable[hash] = i; + } + } + + void do_erase(const K &key, int hash) + { + int last_index = -1; + int index = hashtable.empty() ? -1 : hashtable[hash]; + while (1) { + if (index < 0) + return; + if (ops.cmp(entries[index].udata.first, key)) { + if (last_index < 0) + hashtable[hash] = entries[index].get_next(); + else + entries[last_index].set_next_used(entries[index].get_next()); + entries[index].udata = std::pair(); + entries[index].set_next_free(free_list); + free_list = index; + if (--counter == 0) + init(); + return; + } + last_index = index; + index = entries[index].get_next(); + } + } + + int lookup_index(const K &key, int hash) const + { + int index = hashtable.empty() ? -1 : hashtable[hash]; + while (1) { + if (index < 0) + return -1; + if (ops.cmp(entries[index].udata.first, key)) + return index; + index = entries[index].get_next(); + } + } + + int insert_at(const std::pair &value, int hash) + { + if (free_list < 0) + { + int i = entries.size(); + int new_size = hashtable_size(HASHLIB_SIZE_FACTOR * entries.size()); + hashtable.resize(new_size); + entries.resize(new_size / HASHLIB_SIZE_FACTOR + 1); + entries[i].udata = value; + entries[i].set_next_used(0); + counter++; + rehash(); + return i; + } + + int i = free_list; + free_list = entries[i].get_next(); + entries[i].udata = value; + entries[i].set_next_used(hashtable[hash]); + hashtable[hash] = i; + counter++; + return i; + } + +public: + class iterator + { + dict *ptr; + int index; + public: + iterator() { } + iterator(dict *ptr, int index) : ptr(ptr), index(index) { } + iterator operator++() { do index++; while (index != int(ptr->entries.size()) && ptr->entries[index].is_free()); return *this; } + iterator operator--() { do index--; while (index != 0 && ptr->entries[index].is_free()); return *this; } + bool operator==(const iterator &other) const { return index == other.index; } + bool operator!=(const iterator &other) const { return index != other.index; } + std::pair &operator*() { return ptr->entries[index].udata; } + std::pair *operator->() { return &ptr->entries[index].udata; } + const std::pair &operator*() const { return ptr->entries[index].udata; } + const std::pair *operator->() const { return &ptr->entries[index].udata; } + }; + + class const_iterator + { + const dict *ptr; + int index; + public: + const_iterator() { } + const_iterator(const dict *ptr, int index) : ptr(ptr), index(index) { } + const_iterator operator++() { do index++; while (index != int(ptr->entries.size()) && ptr->entries[index].is_free()); return *this; } + const_iterator operator--() { do index--; while (index != 0 && ptr->entries[index].is_free()); return *this; } + bool operator==(const const_iterator &other) const { return index == other.index; } + bool operator!=(const const_iterator &other) const { return index != other.index; } + const std::pair &operator*() const { return ptr->entries[index].udata; } + const std::pair *operator->() const { return &ptr->entries[index].udata; } + }; + + dict() + { + init(); + } + + dict(const dict &other) + { + init_from(other); + } + + dict(dict &&other) + { + free_list = -1; + counter = 0; + swap(other); + } + + dict &operator=(const dict &other) { + clear(); + init_from(other); + return *this; + } + + dict &operator=(dict &&other) { + clear(); + swap(other); + return *this; + } + + dict(const std::initializer_list> &list) + { + init(); + for (auto &it : list) + insert(it); + } + + template + dict(InputIterator first, InputIterator last) + { + init(); + insert(first, last); + } + + template + void insert(InputIterator first, InputIterator last) + { + for (; first != last; ++first) + insert(*first); + } + + std::pair insert(const std::pair &value) + { + int hash = mkhash(value.first); + int i = lookup_index(value.first, hash); + if (i >= 0) + return std::pair(iterator(this, i), false); + i = insert_at(value, hash); + return std::pair(iterator(this, i), true); + } + + void erase(const K &key) + { + int hash = mkhash(key); + do_erase(key, hash); + } + + void erase(const iterator it) + { + int hash = mkhash(it->first); + do_erase(it->first, hash); + } + + int count(const K &key) const + { + int hash = mkhash(key); + int i = lookup_index(key, hash); + return i < 0 ? 0 : 1; + } + + iterator find(const K &key) + { + int hash = mkhash(key); + int i = lookup_index(key, hash); + if (i < 0) + return end(); + return iterator(this, i); + } + + const_iterator find(const K &key) const + { + int hash = mkhash(key); + int i = lookup_index(key, hash); + if (i < 0) + return end(); + return const_iterator(this, i); + } + + T& at(const K &key) + { + int hash = mkhash(key); + int i = lookup_index(key, hash); + if (i < 0) + throw std::out_of_range("dict::at()"); + return entries[i].udata.second; + } + + const T& at(const K &key) const + { + int hash = mkhash(key); + int i = lookup_index(key, hash); + if (i < 0) + throw std::out_of_range("dict::at()"); + return entries[i].udata.second; + } + + T& operator[](const K &key) + { + int hash = mkhash(key); + int i = lookup_index(key, hash); + if (i < 0) + i = insert_at(std::pair(key, T()), hash); + return entries[i].udata.second; + } + + void swap(dict &other) + { + hashtable.swap(other.hashtable); + entries.swap(other.entries); + std::swap(free_list, other.free_list); + std::swap(counter, other.counter); + } + + bool operator==(const dict &other) const { + if (counter != other.counter) + return false; + if (counter == 0) + return true; + if (entries.size() < other.entries.size()) + for (auto &it : *this) { + auto oit = other.find(it.first); + if (oit == other.end() || oit->second != it.second) + return false; + } + else + for (auto &oit : other) { + auto it = find(oit.first); + if (it == end() || it->second != oit.second) + return false; + } + return true; + } + + bool operator!=(const dict &other) const { + return !(*this == other); + } + + size_t size() const { return counter; } + bool empty() const { return counter == 0; } + void clear() { hashtable.clear(); entries.clear(); init(); } + + iterator begin() { int index = 0; while (index != int(entries.size()) && entries[index].is_free()) index++; return iterator(this, index); } + iterator end() { return iterator(this, entries.size()); } + + const_iterator begin() const { int index = 0; while (index != int(entries.size()) && entries[index].is_free()) index++; return const_iterator(this, index); } + const_iterator end() const { return const_iterator(this, entries.size()); } +}; + +template> +class pool +{ + struct entry_t + { + int link; + K key; + + entry_t() : link(-1) { } + entry_t(const K &key) : link(1), key(key) { } + + bool is_free() const { return link < 0; } + int get_next() const { return (link > 0 ? link : -link) - 2; } + bool get_last() const { return get_next() == -1; } + void set_next_used(int next) { link = next + 2; } + void set_next_free(int next) { link = -(next + 2); } + }; + + std::vector hashtable; + std::vector entries; + int free_list, counter; + OPS ops; + + void init() + { + free_list = -1; + counter = 0; + } + + void init_from(const pool &other) + { + hashtable.clear(); + entries.clear(); + + counter = other.size(); + int new_size = hashtable_size(HASHLIB_SIZE_FACTOR * counter); + hashtable.resize(new_size); + new_size = new_size / HASHLIB_SIZE_FACTOR + 1; + entries.reserve(new_size); + + for (auto &it : other) + entries.push_back(entry_t(it)); + entries.resize(new_size); + rehash(); + } + + int mkhash(const K &key) const + { + unsigned int hash = 0; + if (!hashtable.empty()) + hash = ops.hash(key) % (unsigned int)(hashtable.size()); + return hash; + } + + void rehash() + { + free_list = -1; + + for (auto &h : hashtable) + h = -1; + + for (int i = 0; i < int(entries.size()); i++) + if (entries[i].is_free()) { + entries[i].set_next_free(free_list); + free_list = i; + } else { + int hash = mkhash(entries[i].key); + entries[i].set_next_used(hashtable[hash]); + hashtable[hash] = i; + } + } + + void do_erase(const K &key, int hash) + { + int last_index = -1; + int index = hashtable.empty() ? -1 : hashtable[hash]; + while (1) { + if (index < 0) + return; + if (ops.cmp(entries[index].key, key)) { + if (last_index < 0) + hashtable[hash] = entries[index].get_next(); + else + entries[last_index].set_next_used(entries[index].get_next()); + entries[index].key = K(); + entries[index].set_next_free(free_list); + free_list = index; + if (--counter == 0) + init(); + return; + } + last_index = index; + index = entries[index].get_next(); + } + } + + int lookup_index(const K &key, int hash) const + { + int index = hashtable.empty() ? -1 : hashtable[hash]; + while (1) { + if (index < 0) + return -1; + if (ops.cmp(entries[index].key, key)) + return index; + index = entries[index].get_next(); + } + } + + int insert_at(const K &key, int hash) + { + if (free_list < 0) + { + int i = entries.size(); + int new_size = hashtable_size(HASHLIB_SIZE_FACTOR * entries.size()); + hashtable.resize(new_size); + entries.resize(new_size / HASHLIB_SIZE_FACTOR + 1); + entries[i].key = key; + entries[i].set_next_used(0); + counter++; + rehash(); + return i; + } + + int i = free_list; + free_list = entries[i].get_next(); + entries[i].key = key; + entries[i].set_next_used(hashtable[hash]); + hashtable[hash] = i; + counter++; + return i; + } + +public: + class iterator + { + pool *ptr; + int index; + public: + iterator() { } + iterator(pool *ptr, int index) : ptr(ptr), index(index) { } + iterator operator++() { do index++; while (index != int(ptr->entries.size()) && ptr->entries[index].is_free()); return *this; } + iterator operator--() { do index--; while (index != 0 && ptr->entries[index].is_free()); return *this; } + bool operator==(const iterator &other) const { return index == other.index; } + bool operator!=(const iterator &other) const { return index != other.index; } + K &operator*() { return ptr->entries[index].key; } + K *operator->() { return &ptr->entries[index].key; } + const K &operator*() const { return ptr->entries[index].key; } + const K *operator->() const { return &ptr->entries[index].key; } + }; + + class const_iterator + { + const pool *ptr; + int index; + public: + const_iterator() { } + const_iterator(const pool *ptr, int index) : ptr(ptr), index(index) { } + const_iterator operator++() { do index++; while (index != int(ptr->entries.size()) && ptr->entries[index].is_free()); return *this; } + const_iterator operator--() { do index--; while (index != 0 && ptr->entries[index].is_free()); return *this; } + bool operator==(const const_iterator &other) const { return index == other.index; } + bool operator!=(const const_iterator &other) const { return index != other.index; } + const K &operator*() const { return ptr->entries[index].key; } + const K *operator->() const { return &ptr->entries[index].key; } + }; + + pool() + { + init(); + } + + pool(const pool &other) + { + init_from(other); + } + + pool(pool &&other) + { + free_list = -1; + counter = 0; + swap(other); + } + + pool &operator=(const pool &other) { + clear(); + init_from(other); + return *this; + } + + pool &operator=(pool &&other) { + clear(); + swap(other); + return *this; + } + + pool(const std::initializer_list &list) + { + init(); + for (auto &it : list) + insert(it); + } + + template + pool(InputIterator first, InputIterator last) + { + init(); + insert(first, last); + } + + template + void insert(InputIterator first, InputIterator last) + { + for (; first != last; ++first) + insert(*first); + } + + std::pair insert(const K &key) + { + int hash = mkhash(key); + int i = lookup_index(key, hash); + if (i >= 0) + return std::pair(iterator(this, i), false); + i = insert_at(key, hash); + return std::pair(iterator(this, i), true); + } + + void erase(const K &key) + { + int hash = mkhash(key); + do_erase(key, hash); + } + + void erase(const iterator it) + { + int hash = mkhash(*it); + do_erase(*it, hash); + } + + int count(const K &key) const + { + int hash = mkhash(key); + int i = lookup_index(key, hash); + return i < 0 ? 0 : 1; + } + + iterator find(const K &key) + { + int hash = mkhash(key); + int i = lookup_index(key, hash); + if (i < 0) + return end(); + return iterator(this, i); + } + + const_iterator find(const K &key) const + { + int hash = mkhash(key); + int i = lookup_index(key, hash); + if (i < 0) + return end(); + return const_iterator(this, i); + } + + bool operator[](const K &key) const + { + int hash = mkhash(key); + int i = lookup_index(key, hash); + return i >= 0; + } + + void swap(pool &other) + { + hashtable.swap(other.hashtable); + entries.swap(other.entries); + std::swap(free_list, other.free_list); + std::swap(counter, other.counter); + } + + bool operator==(const pool &other) const { + if (counter != other.counter) + return false; + if (counter == 0) + return true; + if (entries.size() < other.entries.size()) + for (auto &it : *this) { + auto oit = other.find(it.first); + if (oit == other.end() || oit->second != it.second) + return false; + } + else + for (auto &oit : other) { + auto it = find(oit.first); + if (it == end() || it->second != oit.second) + return false; + } + return true; + } + + bool operator!=(const pool &other) const { + return !(*this == other); + } + + size_t size() const { return counter; } + bool empty() const { return counter == 0; } + void clear() { hashtable.clear(); entries.clear(); init(); } + + iterator begin() { int index = 0; while (index != int(entries.size()) && entries[index].is_free()) index++; return iterator(this, index); } + iterator end() { return iterator(this, entries.size()); } + + const_iterator begin() const { int index = 0; while (index != int(entries.size()) && entries[index].is_free()) index++; return const_iterator(this, index); } + const_iterator end() const { return const_iterator(this, entries.size()); } +}; + +} /* namespace hashlib */ + +#endif diff --git a/kernel/hashmap.h b/kernel/hashmap.h deleted file mode 100644 index 431e8122e..000000000 --- a/kernel/hashmap.h +++ /dev/null @@ -1,777 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifndef YOSYS_HASHMAP_H - -#include -#include -#include - -#define YOSYS_HASHTABLE_SIZE_FACTOR 3 - -// The XOR version of DJB2 -// (traditionally 5381 is used as starting value for the djb2 hash) -inline unsigned int mkhash(unsigned int a, unsigned int b) { - return ((a << 5) + a) ^ b; -} - -// The ADD version of DJB2 -// (use this version as last call for cache locality in b) -inline unsigned int mkhash_add(unsigned int a, unsigned int b) { - return ((a << 5) + a) + b; -} - -template struct hash_ops { - bool cmp(const T &a, const T &b) const { - return a == b; - } - unsigned int hash(const T &a) const { - return a.hash(); - } -}; - -template<> struct hash_ops { - bool cmp(int a, int b) const { - return a == b; - } - unsigned int hash(int a) const { - return a; - } -}; - -template<> struct hash_ops { - bool cmp(const std::string &a, const std::string &b) const { - return a == b; - } - unsigned int hash(const std::string &a) const { - unsigned int v = 0; - for (auto c : a) - v = mkhash(v, c); - return v; - } -}; - -struct hash_cstr_ops { - bool cmp(const char *a, const char *b) const { - for (int i = 0; a[i] || b[i]; i++) - if (a[i] != b[i]) - return false; - return true; - } - unsigned int hash(const char *a) const { - unsigned int hash = 5381; - while (*a) - hash = mkhash(hash, *(a++)); - return hash; - } -}; - -struct hash_ptr_ops { - bool cmp(const void *a, const void *b) const { - return a == b; - } - unsigned int hash(const void *a) const { - return (unsigned long)a; - } -}; - -struct hash_obj_ops { - bool cmp(const void *a, const void *b) const { - return a == b; - } - template - unsigned int hash(const T *a) const { - return a->name.hash(); - } -}; - -inline int hashtable_size(int old_size) -{ - // prime numbers, approx. in powers of two - if (old_size < 53) return 53; - if (old_size < 113) return 113; - if (old_size < 251) return 251; - if (old_size < 503) return 503; - if (old_size < 1129) return 1129; - if (old_size < 2503) return 2503; - if (old_size < 5023) return 5023; - if (old_size < 11299) return 11299; - if (old_size < 25097) return 25097; - if (old_size < 50291) return 50291; - if (old_size < 112997) return 112997; - if (old_size < 251003) return 251003; - if (old_size < 503003) return 503003; - if (old_size < 1129991) return 1129991; - if (old_size < 2509993) return 2509993; - if (old_size < 5029991) return 5029991; - if (old_size < 11299997) return 11299997; - if (old_size < 25099999) return 25099999; - if (old_size < 50299999) return 50299999; - if (old_size < 113000009) return 113000009; - if (old_size < 250999999) return 250999999; - if (old_size < 503000009) return 503000009; - if (old_size < 1129999999) return 1129999999; - throw std::length_error("hash table exceeded maximum size"); -} - -template> -class dict -{ - struct entry_t - { - int link; - std::pair udata; - - entry_t() : link(-1) { } - entry_t(const std::pair &udata) : link(1), udata(udata) { } - - bool is_free() const { return link < 0; } - int get_next() const { return (link > 0 ? link : -link) - 2; } - bool get_last() const { return get_next() == -1; } - void set_next_used(int next) { link = next + 2; } - void set_next_free(int next) { link = -(next + 2); } - }; - - std::vector hashtable; - std::vector entries; - int free_list, counter; - OPS ops; - - void init() - { - free_list = -1; - counter = 0; - } - - void init_from(const dict &other) - { - hashtable.clear(); - entries.clear(); - - counter = other.size(); - int new_size = hashtable_size(YOSYS_HASHTABLE_SIZE_FACTOR * counter); - hashtable.resize(new_size); - new_size = new_size / YOSYS_HASHTABLE_SIZE_FACTOR + 1; - entries.reserve(new_size); - - for (auto &it : other) - entries.push_back(entry_t(it)); - entries.resize(new_size); - rehash(); - } - - int mkhash(const K &key) const - { - unsigned int hash = 0; - if (!hashtable.empty()) - hash = ops.hash(key) % (unsigned int)(hashtable.size()); - return hash; - } - - void rehash() - { - free_list = -1; - - for (auto &h : hashtable) - h = -1; - - for (int i = 0; i < int(entries.size()); i++) - if (entries[i].is_free()) { - entries[i].set_next_free(free_list); - free_list = i; - } else { - int hash = mkhash(entries[i].udata.first); - entries[i].set_next_used(hashtable[hash]); - hashtable[hash] = i; - } - } - - void do_erase(const K &key, int hash) - { - int last_index = -1; - int index = hashtable.empty() ? -1 : hashtable[hash]; - while (1) { - if (index < 0) - return; - if (ops.cmp(entries[index].udata.first, key)) { - if (last_index < 0) - hashtable[hash] = entries[index].get_next(); - else - entries[last_index].set_next_used(entries[index].get_next()); - entries[index].udata = std::pair(); - entries[index].set_next_free(free_list); - free_list = index; - if (--counter == 0) - init(); - return; - } - last_index = index; - index = entries[index].get_next(); - } - } - - int lookup_index(const K &key, int hash) const - { - int index = hashtable.empty() ? -1 : hashtable[hash]; - while (1) { - if (index < 0) - return -1; - if (ops.cmp(entries[index].udata.first, key)) - return index; - index = entries[index].get_next(); - } - } - - int insert_at(const std::pair &value, int hash) - { - if (free_list < 0) - { - int i = entries.size(); - int new_size = hashtable_size(YOSYS_HASHTABLE_SIZE_FACTOR * entries.size()); - hashtable.resize(new_size); - entries.resize(new_size / YOSYS_HASHTABLE_SIZE_FACTOR + 1); - entries[i].udata = value; - entries[i].set_next_used(0); - counter++; - rehash(); - return i; - } - - int i = free_list; - free_list = entries[i].get_next(); - entries[i].udata = value; - entries[i].set_next_used(hashtable[hash]); - hashtable[hash] = i; - counter++; - return i; - } - -public: - class iterator - { - dict *ptr; - int index; - public: - iterator() { } - iterator(dict *ptr, int index) : ptr(ptr), index(index) { } - iterator operator++() { do index++; while (index != int(ptr->entries.size()) && ptr->entries[index].is_free()); return *this; } - iterator operator--() { do index--; while (index != 0 && ptr->entries[index].is_free()); return *this; } - bool operator==(const iterator &other) const { return index == other.index; } - bool operator!=(const iterator &other) const { return index != other.index; } - std::pair &operator*() { return ptr->entries[index].udata; } - std::pair *operator->() { return &ptr->entries[index].udata; } - const std::pair &operator*() const { return ptr->entries[index].udata; } - const std::pair *operator->() const { return &ptr->entries[index].udata; } - }; - - class const_iterator - { - const dict *ptr; - int index; - public: - const_iterator() { } - const_iterator(const dict *ptr, int index) : ptr(ptr), index(index) { } - const_iterator operator++() { do index++; while (index != int(ptr->entries.size()) && ptr->entries[index].is_free()); return *this; } - const_iterator operator--() { do index--; while (index != 0 && ptr->entries[index].is_free()); return *this; } - bool operator==(const const_iterator &other) const { return index == other.index; } - bool operator!=(const const_iterator &other) const { return index != other.index; } - const std::pair &operator*() const { return ptr->entries[index].udata; } - const std::pair *operator->() const { return &ptr->entries[index].udata; } - }; - - dict() - { - init(); - } - - dict(const dict &other) - { - init_from(other); - } - - dict(dict &&other) - { - free_list = -1; - counter = 0; - swap(other); - } - - dict &operator=(const dict &other) { - clear(); - init_from(other); - return *this; - } - - dict &operator=(dict &&other) { - clear(); - swap(other); - return *this; - } - - dict(const std::initializer_list> &list) - { - init(); - for (auto &it : list) - insert(it); - } - - template - dict(InputIterator first, InputIterator last) - { - init(); - insert(first, last); - } - - template - void insert(InputIterator first, InputIterator last) - { - for (; first != last; ++first) - insert(*first); - } - - iterator insert(const std::pair &value) - { - int hash = mkhash(value.first); - int i = lookup_index(value.first, hash); - if (i >= 0) - return iterator(this, i); - i = insert_at(value, hash); - return iterator(this, i); - } - - void erase(const K &key) - { - int hash = mkhash(key); - do_erase(key, hash); - } - - void erase(const iterator it) - { - int hash = mkhash(it->first); - do_erase(it->first, hash); - } - - int count(const K &key) const - { - int hash = mkhash(key); - int i = lookup_index(key, hash); - return i < 0 ? 0 : 1; - } - - iterator find(const K &key) - { - int hash = mkhash(key); - int i = lookup_index(key, hash); - if (i < 0) - return end(); - return iterator(this, i); - } - - const_iterator find(const K &key) const - { - int hash = mkhash(key); - int i = lookup_index(key, hash); - if (i < 0) - return end(); - return const_iterator(this, i); - } - - T& at(const K &key) - { - int hash = mkhash(key); - int i = lookup_index(key, hash); - if (i < 0) - throw std::out_of_range("dict::at()"); - return entries[i].udata.second; - } - - const T& at(const K &key) const - { - int hash = mkhash(key); - int i = lookup_index(key, hash); - if (i < 0) - throw std::out_of_range("dict::at()"); - return entries[i].udata.second; - } - - T& operator[](const K &key) - { - int hash = mkhash(key); - int i = lookup_index(key, hash); - if (i < 0) - i = insert_at(std::pair(key, T()), hash); - return entries[i].udata.second; - } - - void swap(dict &other) - { - hashtable.swap(other.hashtable); - entries.swap(other.entries); - std::swap(free_list, other.free_list); - std::swap(counter, other.counter); - } - - bool operator==(const dict &other) const { - if (counter != other.counter) - return false; - if (counter == 0) - return true; - if (entries.size() < other.entries.size()) - for (auto &it : *this) { - auto oit = other.find(it.first); - if (oit == other.end() || oit->second != it.second) - return false; - } - else - for (auto &oit : other) { - auto it = find(oit.first); - if (it == end() || it->second != oit.second) - return false; - } - return true; - } - - bool operator!=(const dict &other) const { - return !(*this == other); - } - - size_t size() const { return counter; } - bool empty() const { return counter == 0; } - void clear() { hashtable.clear(); entries.clear(); init(); } - - iterator begin() { int index = 0; while (index != int(entries.size()) && entries[index].is_free()) index++; return iterator(this, index); } - iterator end() { return iterator(this, entries.size()); } - - const_iterator begin() const { int index = 0; while (index != int(entries.size()) && entries[index].is_free()) index++; return const_iterator(this, index); } - const_iterator end() const { return const_iterator(this, entries.size()); } -}; - -template> -class pool -{ - struct entry_t - { - int link; - K key; - - entry_t() : link(-1) { } - entry_t(const K &key) : link(1), key(key) { } - - bool is_free() const { return link < 0; } - int get_next() const { return (link > 0 ? link : -link) - 2; } - bool get_last() const { return get_next() == -1; } - void set_next_used(int next) { link = next + 2; } - void set_next_free(int next) { link = -(next + 2); } - }; - - std::vector hashtable; - std::vector entries; - int free_list, counter; - OPS ops; - - void init() - { - free_list = -1; - counter = 0; - } - - void init_from(const pool &other) - { - hashtable.clear(); - entries.clear(); - - counter = other.size(); - int new_size = hashtable_size(YOSYS_HASHTABLE_SIZE_FACTOR * counter); - hashtable.resize(new_size); - new_size = new_size / YOSYS_HASHTABLE_SIZE_FACTOR + 1; - entries.reserve(new_size); - - for (auto &it : other) - entries.push_back(entry_t(it)); - entries.resize(new_size); - rehash(); - } - - int mkhash(const K &key) const - { - unsigned int hash = 0; - if (!hashtable.empty()) - hash = ops.hash(key) % (unsigned int)(hashtable.size()); - return hash; - } - - void rehash() - { - free_list = -1; - - for (auto &h : hashtable) - h = -1; - - for (int i = 0; i < int(entries.size()); i++) - if (entries[i].is_free()) { - entries[i].set_next_free(free_list); - free_list = i; - } else { - int hash = mkhash(entries[i].key); - entries[i].set_next_used(hashtable[hash]); - hashtable[hash] = i; - } - } - - void do_erase(const K &key, int hash) - { - int last_index = -1; - int index = hashtable.empty() ? -1 : hashtable[hash]; - while (1) { - if (index < 0) - return; - if (ops.cmp(entries[index].key, key)) { - if (last_index < 0) - hashtable[hash] = entries[index].get_next(); - else - entries[last_index].set_next_used(entries[index].get_next()); - entries[index].key = K(); - entries[index].set_next_free(free_list); - free_list = index; - if (--counter == 0) - init(); - return; - } - last_index = index; - index = entries[index].get_next(); - } - } - - int lookup_index(const K &key, int hash) const - { - int index = hashtable.empty() ? -1 : hashtable[hash]; - while (1) { - if (index < 0) - return -1; - if (ops.cmp(entries[index].key, key)) - return index; - index = entries[index].get_next(); - } - } - - int insert_at(const K &key, int hash) - { - if (free_list < 0) - { - int i = entries.size(); - int new_size = hashtable_size(YOSYS_HASHTABLE_SIZE_FACTOR * entries.size()); - hashtable.resize(new_size); - entries.resize(new_size / YOSYS_HASHTABLE_SIZE_FACTOR + 1); - entries[i].key = key; - entries[i].set_next_used(0); - counter++; - rehash(); - return i; - } - - int i = free_list; - free_list = entries[i].get_next(); - entries[i].key = key; - entries[i].set_next_used(hashtable[hash]); - hashtable[hash] = i; - counter++; - return i; - } - -public: - class iterator - { - pool *ptr; - int index; - public: - iterator() { } - iterator(pool *ptr, int index) : ptr(ptr), index(index) { } - iterator operator++() { do index++; while (index != int(ptr->entries.size()) && ptr->entries[index].is_free()); return *this; } - iterator operator--() { do index--; while (index != 0 && ptr->entries[index].is_free()); return *this; } - bool operator==(const iterator &other) const { return index == other.index; } - bool operator!=(const iterator &other) const { return index != other.index; } - K &operator*() { return ptr->entries[index].key; } - K *operator->() { return &ptr->entries[index].key; } - const K &operator*() const { return ptr->entries[index].key; } - const K *operator->() const { return &ptr->entries[index].key; } - }; - - class const_iterator - { - const pool *ptr; - int index; - public: - const_iterator() { } - const_iterator(const pool *ptr, int index) : ptr(ptr), index(index) { } - const_iterator operator++() { do index++; while (index != int(ptr->entries.size()) && ptr->entries[index].is_free()); return *this; } - const_iterator operator--() { do index--; while (index != 0 && ptr->entries[index].is_free()); return *this; } - bool operator==(const const_iterator &other) const { return index == other.index; } - bool operator!=(const const_iterator &other) const { return index != other.index; } - const K &operator*() const { return ptr->entries[index].key; } - const K *operator->() const { return &ptr->entries[index].key; } - }; - - pool() - { - init(); - } - - pool(const pool &other) - { - init_from(other); - } - - pool(pool &&other) - { - free_list = -1; - counter = 0; - swap(other); - } - - pool &operator=(const pool &other) { - clear(); - init_from(other); - return *this; - } - - pool &operator=(pool &&other) { - clear(); - swap(other); - return *this; - } - - pool(const std::initializer_list &list) - { - init(); - for (auto &it : list) - insert(it); - } - - template - pool(InputIterator first, InputIterator last) - { - init(); - insert(first, last); - } - - template - void insert(InputIterator first, InputIterator last) - { - for (; first != last; ++first) - insert(*first); - } - - iterator insert(const K &key) - { - int hash = mkhash(key); - int i = lookup_index(key, hash); - if (i >= 0) - return iterator(this, i); - i = insert_at(key, hash); - return iterator(this, i); - } - - void erase(const K &key) - { - int hash = mkhash(key); - do_erase(key, hash); - } - - void erase(const iterator it) - { - int hash = mkhash(it->first); - do_erase(it->first, hash); - } - - int count(const K &key) const - { - int hash = mkhash(key); - int i = lookup_index(key, hash); - return i < 0 ? 0 : 1; - } - - iterator find(const K &key) - { - int hash = mkhash(key); - int i = lookup_index(key, hash); - if (i < 0) - return end(); - return iterator(this, i); - } - - const_iterator find(const K &key) const - { - int hash = mkhash(key); - int i = lookup_index(key, hash); - if (i < 0) - return end(); - return const_iterator(this, i); - } - - bool operator[](const K &key) const - { - int hash = mkhash(key); - int i = lookup_index(key, hash); - return i >= 0; - } - - void swap(pool &other) - { - hashtable.swap(other.hashtable); - entries.swap(other.entries); - std::swap(free_list, other.free_list); - std::swap(counter, other.counter); - } - - bool operator==(const pool &other) const { - if (counter != other.counter) - return false; - if (counter == 0) - return true; - if (entries.size() < other.entries.size()) - for (auto &it : *this) { - auto oit = other.find(it.first); - if (oit == other.end() || oit->second != it.second) - return false; - } - else - for (auto &oit : other) { - auto it = find(oit.first); - if (it == end() || it->second != oit.second) - return false; - } - return true; - } - - bool operator!=(const pool &other) const { - return !(*this == other); - } - - size_t size() const { return counter; } - bool empty() const { return counter == 0; } - void clear() { hashtable.clear(); entries.clear(); init(); } - - iterator begin() { int index = 0; while (index != int(entries.size()) && entries[index].is_free()) index++; return iterator(this, index); } - iterator end() { return iterator(this, entries.size()); } - - const_iterator begin() const { int index = 0; while (index != int(entries.size()) && entries[index].is_free()) index++; return const_iterator(this, index); } - const_iterator end() const { return const_iterator(this, entries.size()); } -}; - -#endif diff --git a/kernel/modtools.h b/kernel/modtools.h index 56362dbc8..558cc08b8 100644 --- a/kernel/modtools.h +++ b/kernel/modtools.h @@ -270,7 +270,7 @@ struct ModWalker dict> signal_consumers; pool signal_inputs, signal_outputs; - dict, hash_obj_ops> cell_outputs, cell_inputs; + dict> cell_outputs, cell_inputs; void add_wire(RTLIL::Wire *wire) { diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 23edcceef..c262801dc 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -236,6 +236,9 @@ void RTLIL::Selection::optimize(RTLIL::Design *design) RTLIL::Design::Design() { + unsigned int hashidx_count = 0; + hashidx_ = hashidx_count++; + refcount_modules_ = 0; selection_stack.push_back(RTLIL::Selection()); } @@ -447,6 +450,9 @@ std::vector RTLIL::Design::selected_whole_modules_warn() const RTLIL::Module::Module() { + unsigned int hashidx_count = 0; + hashidx_ = hashidx_count++; + design = nullptr; refcount_wires_ = 0; refcount_cells_ = 0; @@ -1132,7 +1138,7 @@ namespace { struct DeleteWireWorker { RTLIL::Module *module; - const pool *wires_p; + const pool *wires_p; void operator()(RTLIL::SigSpec &sig) { std::vector chunks = sig; @@ -1146,7 +1152,7 @@ namespace { }; } -void RTLIL::Module::remove(const pool &wires) +void RTLIL::Module::remove(const pool &wires) { log_assert(refcount_wires_ == 0); @@ -1735,6 +1741,9 @@ RTLIL::Cell* RTLIL::Module::addDlatchsrGate(RTLIL::IdString name, RTLIL::SigSpec RTLIL::Wire::Wire() { + unsigned int hashidx_count = 0; + hashidx_ = hashidx_count++; + module = nullptr; width = 1; start_offset = 0; @@ -1746,12 +1755,17 @@ RTLIL::Wire::Wire() RTLIL::Memory::Memory() { + unsigned int hashidx_count = 0; + hashidx_ = hashidx_count++; + width = 1; size = 0; } RTLIL::Cell::Cell() : module(nullptr) { + unsigned int hashidx_count = 0; + hashidx_ = hashidx_count++; } bool RTLIL::Cell::hasPort(RTLIL::IdString portname) const diff --git a/kernel/rtlil.h b/kernel/rtlil.h index cb654c3af..8cf707999 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -708,8 +708,14 @@ struct RTLIL::Selection struct RTLIL::Monitor { - RTLIL::IdString name; - Monitor() { name = stringf("$%d", autoidx++); } + unsigned int hashidx_; + unsigned int hash() const { return hashidx_; } + + Monitor() { + unsigned int hashidx_count = 0; + hashidx_ = hashidx_count++; + } + virtual ~Monitor() { } virtual void notify_module_add(RTLIL::Module*) { } virtual void notify_module_del(RTLIL::Module*) { } @@ -721,7 +727,10 @@ struct RTLIL::Monitor struct RTLIL::Design { - pool monitors; + unsigned int hashidx_; + unsigned int hash() const { return hashidx_; } + + pool monitors; dict scratchpad; int refcount_modules_; @@ -802,13 +811,16 @@ struct RTLIL::Design struct RTLIL::Module { + unsigned int hashidx_; + unsigned int hash() const { return hashidx_; } + protected: void add(RTLIL::Wire *wire); void add(RTLIL::Cell *cell); public: RTLIL::Design *design; - pool monitors; + pool monitors; int refcount_wires_; int refcount_cells_; @@ -862,7 +874,7 @@ public: RTLIL::ObjRange cells() { return RTLIL::ObjRange(&cells_, &refcount_cells_); } // Removing wires is expensive. If you have to remove wires, remove them all at once. - void remove(const pool &wires); + void remove(const pool &wires); void remove(RTLIL::Cell *cell); void rename(RTLIL::Wire *wire, RTLIL::IdString new_name); @@ -1031,6 +1043,9 @@ public: struct RTLIL::Wire { + unsigned int hashidx_; + unsigned int hash() const { return hashidx_; } + protected: // use module->addWire() and module->remove() to create or destroy wires friend struct RTLIL::Module; @@ -1051,6 +1066,9 @@ public: struct RTLIL::Memory { + unsigned int hashidx_; + unsigned int hash() const { return hashidx_; } + Memory(); RTLIL::IdString name; @@ -1060,6 +1078,9 @@ struct RTLIL::Memory struct RTLIL::Cell { + unsigned int hashidx_; + unsigned int hash() const { return hashidx_; } + protected: // use module->addCell() and module->remove() to create or destroy cells friend struct RTLIL::Module; diff --git a/kernel/yosys.h b/kernel/yosys.h index d47f3a958..b653941ce 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -124,17 +124,51 @@ YOSYS_NAMESPACE_BEGIN -#include "kernel/hashmap.h" +#include "kernel/hashlib.h" using std::vector; +using std::string; +using hashlib::mkhash; +using hashlib::mkhash_add; +using hashlib::hash_ops; +using hashlib::hash_cstr_ops; +using hashlib::hash_ptr_ops; +using hashlib::hash_obj_ops; +using hashlib::dict; +using hashlib::pool; namespace RTLIL { struct IdString; + struct Const; struct SigBit; struct SigSpec; struct Wire; struct Cell; + struct Module; + struct Design; + struct Monitor; } +using RTLIL::IdString; +using RTLIL::Const; +using RTLIL::SigBit; +using RTLIL::SigSpec; +using RTLIL::Wire; +using RTLIL::Cell; +using RTLIL::Module; +using RTLIL::Design; + +template<> struct hash_ops : hash_obj_ops {}; +template<> struct hash_ops : hash_obj_ops {}; +template<> struct hash_ops : hash_obj_ops {}; +template<> struct hash_ops : hash_obj_ops {}; +template<> struct hash_ops : hash_obj_ops {}; + +template<> struct hash_ops : hash_obj_ops {}; +template<> struct hash_ops : hash_obj_ops {}; +template<> struct hash_ops : hash_obj_ops {}; +template<> struct hash_ops : hash_obj_ops {}; +template<> struct hash_ops : hash_obj_ops {}; + std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)); std::string vstringf(const char *fmt, va_list ap); int readsome(std::istream &f, char *s, int n); diff --git a/passes/cmds/delete.cc b/passes/cmds/delete.cc index 5bf2a36b8..b4362887e 100644 --- a/passes/cmds/delete.cc +++ b/passes/cmds/delete.cc @@ -91,8 +91,8 @@ struct DeletePass : public Pass { continue; } - pool delete_wires; - pool delete_cells; + pool delete_wires; + pool delete_cells; pool delete_procs; pool delete_mems; diff --git a/passes/cmds/splitnets.cc b/passes/cmds/splitnets.cc index 2523c1660..d4e721a5d 100644 --- a/passes/cmds/splitnets.cc +++ b/passes/cmds/splitnets.cc @@ -176,7 +176,7 @@ struct SplitnetsPass : public Pass { module->rewrite_sigspecs(worker); - pool delete_wires; + pool delete_wires; for (auto &it : worker.splitmap) delete_wires.insert(it.first); module->remove(delete_wires); diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index b387e0381..b9ff5d302 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -262,7 +262,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos } - pool del_wires; + pool del_wires; int del_wires_count = 0; for (auto wire : maybe_del_wires) diff --git a/passes/opt/opt_const.cc b/passes/opt/opt_const.cc index f78ea6cc3..7f800bde9 100644 --- a/passes/opt/opt_const.cc +++ b/passes/opt/opt_const.cc @@ -199,7 +199,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons dict invert_map; TopoSort> cells; - dict, hash_obj_ops> cell_to_inbit; + dict> cell_to_inbit; dict> outbit_to_cell; for (auto cell : module->cells()) diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc index 91bfd58ab..c581b749e 100644 --- a/passes/opt/opt_share.cc +++ b/passes/opt/opt_share.cc @@ -41,7 +41,7 @@ struct OptShareWorker CellTypes ct; int total_count; #ifdef USE_CELL_HASH_CACHE - dict cell_hash_cache; + dict cell_hash_cache; #endif #ifdef USE_CELL_HASH_CACHE diff --git a/passes/opt/share.cc b/passes/opt/share.cc index 41a4a6908..0d1a54d97 100644 --- a/passes/opt/share.cc +++ b/passes/opt/share.cc @@ -731,7 +731,7 @@ struct ShareWorker return forbidden_controls_cache.at(cell); pool pbits; - pool consumer_cells; + pool consumer_cells; modwalker.get_consumers(pbits, modwalker.cell_outputs[cell]); @@ -803,7 +803,7 @@ struct ShareWorker return activation_patterns_cache.at(cell); const pool &cell_out_bits = modwalker.cell_outputs[cell]; - pool driven_cells, driven_data_muxes; + pool driven_cells, driven_data_muxes; for (auto &bit : cell_out_bits) {