mirror of
https://github.com/YosysHQ/yosys.git
synced 2026-10-06 10:03:36 +02:00
twine: refactor
This commit is contained in:
@@ -43,6 +43,7 @@ yosys_core(kernel
|
||||
gzip.cc
|
||||
gzip.h
|
||||
hashcons.h
|
||||
hashcons_impl.h
|
||||
hashlib.h
|
||||
io.cc
|
||||
io.h
|
||||
@@ -133,6 +134,7 @@ yosys_core(kernel
|
||||
fmt.h
|
||||
gzip.h
|
||||
hashcons.h
|
||||
hashcons_impl.h
|
||||
hashlib.h
|
||||
io.h
|
||||
json.h
|
||||
|
||||
+12
-118
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "kernel/yosys_common.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <bit>
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
@@ -25,28 +24,13 @@ public:
|
||||
Derived* self() { return static_cast<Derived*>(this); }
|
||||
const Derived* self() const { return static_cast<const Derived*>(this); }
|
||||
|
||||
HashConsPool() { rebuild_index(); }
|
||||
HashConsPool();
|
||||
HashConsPool(const HashConsPool& other) = default;
|
||||
HashConsPool(HashConsPool&& other)
|
||||
: backing(std::move(other.backing)), table(std::move(other.table)), free_list(std::move(other.free_list)) {
|
||||
other.reset();
|
||||
}
|
||||
HashConsPool(HashConsPool&& other);
|
||||
HashConsPool& operator=(const HashConsPool& other) = default;
|
||||
HashConsPool& operator=(HashConsPool&& other) {
|
||||
if (this != &other) {
|
||||
backing = std::move(other.backing);
|
||||
table = std::move(other.table);
|
||||
free_list = std::move(other.free_list);
|
||||
other.reset();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
HashConsPool& operator=(HashConsPool&& other);
|
||||
|
||||
void reset() {
|
||||
backing.clear();
|
||||
free_list.clear();
|
||||
rebuild_index();
|
||||
}
|
||||
void reset();
|
||||
|
||||
static bool is_static(Ref ref) {
|
||||
if constexpr (Derived::STATIC_COUNT == 0)
|
||||
@@ -115,17 +99,7 @@ public:
|
||||
|
||||
static void check_ready() {}
|
||||
|
||||
void rebuild_index() {
|
||||
Derived::check_ready();
|
||||
free_list.clear();
|
||||
for (size_t idx = 0; idx < backing.size(); ++idx)
|
||||
if (backing[idx].is_dead())
|
||||
free_list.push_back(idx);
|
||||
std::sort(free_list.begin(), free_list.end(), std::greater<size_t>());
|
||||
table.assign(std::bit_ceil((Derived::STATIC_COUNT + size()) * 2 + 2), Ref());
|
||||
for (Ref ref : refs())
|
||||
index_insert(ref);
|
||||
}
|
||||
void rebuild_index();
|
||||
|
||||
size_t home_slot(uint64_t hash) const {
|
||||
// Knuth's Fibonacci hashing saves us from how bad DJB2 is
|
||||
@@ -135,67 +109,11 @@ public:
|
||||
size_t next_slot(size_t slot) const { return (slot + 1) & (table.size() - 1); }
|
||||
|
||||
template<typename Eq>
|
||||
Ref find_hashed(uint64_t hash, Eq&& eq) const {
|
||||
for (size_t slot = home_slot(hash); table[slot] != Ref(); slot = next_slot(slot)) {
|
||||
Ref ref = table[slot];
|
||||
if (Derived::hash_node((*this)[ref]) == hash && eq(ref))
|
||||
return ref;
|
||||
}
|
||||
return Ref();
|
||||
}
|
||||
|
||||
void index_insert(Ref ref) {
|
||||
size_t slot = home_slot(Derived::hash_node((*this)[ref]));
|
||||
while (table[slot] != Ref())
|
||||
slot = next_slot(slot);
|
||||
table[slot] = ref;
|
||||
}
|
||||
|
||||
void index_erase(Ref ref) {
|
||||
size_t hole = home_slot(Derived::hash_node((*this)[ref]));
|
||||
while (table[hole] != ref)
|
||||
hole = next_slot(hole);
|
||||
size_t mask = table.size() - 1;
|
||||
for (size_t slot = next_slot(hole); table[slot] != Ref(); slot = next_slot(slot)) {
|
||||
size_t home = home_slot(Derived::hash_node((*this)[table[slot]]));
|
||||
if (((slot - home) & mask) >= ((slot - hole) & mask)) {
|
||||
table[hole] = table[slot];
|
||||
hole = slot;
|
||||
}
|
||||
}
|
||||
table[hole] = Ref();
|
||||
}
|
||||
|
||||
void grow_index() {
|
||||
std::vector<Ref> old(table.size() * 2, Ref());
|
||||
std::swap(old, table);
|
||||
for (Ref ref : old)
|
||||
if (ref != Ref())
|
||||
index_insert(ref);
|
||||
}
|
||||
|
||||
Ref add_inner(Node t) {
|
||||
Ref ref;
|
||||
if (!free_list.empty()) {
|
||||
size_t idx = free_list.back();
|
||||
free_list.pop_back();
|
||||
backing[idx] = std::move(t);
|
||||
ref = Ref(Derived::STATIC_COUNT + idx);
|
||||
} else {
|
||||
ref = Ref(Derived::STATIC_COUNT + backing.size());
|
||||
backing.push_back(std::move(t));
|
||||
}
|
||||
if ((Derived::STATIC_COUNT + size()) * 3 > table.size() * 2)
|
||||
grow_index();
|
||||
index_insert(ref);
|
||||
if (yosys_xtrace) {
|
||||
std::cout << "#X# add_inner added ";
|
||||
self()->dump(ref);
|
||||
std::cout << "\n";
|
||||
std::cout << "#X# as integer " << ref.raw() << "\n";
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
Ref find_hashed(uint64_t hash, Eq&& eq) const;
|
||||
void index_insert(Ref ref);
|
||||
void index_erase(Ref ref);
|
||||
void grow_index();
|
||||
Ref add_inner(Node t);
|
||||
|
||||
size_t size() const { return backing.size() - free_list.size(); }
|
||||
|
||||
@@ -206,32 +124,8 @@ public:
|
||||
}
|
||||
|
||||
template<typename Roots>
|
||||
size_t gc(const Roots& roots) {
|
||||
pool<Ref> live;
|
||||
for (Ref ref : roots)
|
||||
mark_live(ref, live);
|
||||
size_t erased = 0;
|
||||
for (size_t idx = 0; idx < backing.size(); ++idx) {
|
||||
if (backing[idx].is_dead())
|
||||
continue;
|
||||
if (!live.count(Ref(Derived::STATIC_COUNT + idx))) {
|
||||
index_erase(Ref(Derived::STATIC_COUNT + idx));
|
||||
free_list.push_back(idx);
|
||||
backing[idx] = Node{};
|
||||
erased++;
|
||||
}
|
||||
}
|
||||
// TODO something like YOSYS_SORT_ID_FREE_LIST to make it optional?
|
||||
std::sort(free_list.begin(), free_list.end(), std::greater<size_t>());
|
||||
return erased;
|
||||
}
|
||||
|
||||
void mark_live(Ref ref, pool<Ref>& live) const {
|
||||
ref = ref.untag();
|
||||
if (ref == Ref() || is_static(ref) || !live.insert(ref).second)
|
||||
return;
|
||||
Derived::for_each_child((*this)[ref], [&](Ref child) { mark_live(child, live); });
|
||||
}
|
||||
size_t gc(const Roots& roots);
|
||||
void mark_live(Ref ref, pool<Ref>& live) const;
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
#ifndef YOSYS_HASHCONS_IMPL_H
|
||||
#define YOSYS_HASHCONS_IMPL_H
|
||||
|
||||
#include "kernel/hashcons.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
template<typename Derived, typename Node, typename Ref>
|
||||
HashConsPool<Derived, Node, Ref>::HashConsPool() { rebuild_index(); }
|
||||
|
||||
template<typename Derived, typename Node, typename Ref>
|
||||
HashConsPool<Derived, Node, Ref>::HashConsPool(HashConsPool&& other)
|
||||
: backing(std::move(other.backing)), table(std::move(other.table)), free_list(std::move(other.free_list)) {
|
||||
other.reset();
|
||||
}
|
||||
|
||||
template<typename Derived, typename Node, typename Ref>
|
||||
HashConsPool<Derived, Node, Ref>& HashConsPool<Derived, Node, Ref>::operator=(HashConsPool&& other) {
|
||||
if (this != &other) {
|
||||
backing = std::move(other.backing);
|
||||
table = std::move(other.table);
|
||||
free_list = std::move(other.free_list);
|
||||
other.reset();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Derived, typename Node, typename Ref>
|
||||
void HashConsPool<Derived, Node, Ref>::reset() {
|
||||
backing.clear();
|
||||
free_list.clear();
|
||||
rebuild_index();
|
||||
}
|
||||
|
||||
template<typename Derived, typename Node, typename Ref>
|
||||
void HashConsPool<Derived, Node, Ref>::rebuild_index() {
|
||||
Derived::check_ready();
|
||||
free_list.clear();
|
||||
for (size_t idx = 0; idx < backing.size(); ++idx)
|
||||
if (backing[idx].is_dead())
|
||||
free_list.push_back(idx);
|
||||
std::sort(free_list.begin(), free_list.end(), std::greater<size_t>());
|
||||
table.assign(std::bit_ceil((Derived::STATIC_COUNT + size()) * 2 + 2), Ref());
|
||||
for (Ref ref : refs())
|
||||
index_insert(ref);
|
||||
}
|
||||
|
||||
template<typename Derived, typename Node, typename Ref>
|
||||
template<typename Eq>
|
||||
Ref HashConsPool<Derived, Node, Ref>::find_hashed(uint64_t hash, Eq&& eq) const {
|
||||
for (size_t slot = home_slot(hash); table[slot] != Ref(); slot = next_slot(slot)) {
|
||||
Ref ref = table[slot];
|
||||
if (Derived::hash_node((*this)[ref]) == hash && eq(ref))
|
||||
return ref;
|
||||
}
|
||||
return Ref();
|
||||
}
|
||||
|
||||
template<typename Derived, typename Node, typename Ref>
|
||||
void HashConsPool<Derived, Node, Ref>::index_insert(Ref ref) {
|
||||
size_t slot = home_slot(Derived::hash_node((*this)[ref]));
|
||||
while (table[slot] != Ref())
|
||||
slot = next_slot(slot);
|
||||
table[slot] = ref;
|
||||
}
|
||||
|
||||
template<typename Derived, typename Node, typename Ref>
|
||||
void HashConsPool<Derived, Node, Ref>::index_erase(Ref ref) {
|
||||
size_t hole = home_slot(Derived::hash_node((*this)[ref]));
|
||||
while (table[hole] != ref)
|
||||
hole = next_slot(hole);
|
||||
size_t mask = table.size() - 1;
|
||||
for (size_t slot = next_slot(hole); table[slot] != Ref(); slot = next_slot(slot)) {
|
||||
size_t home = home_slot(Derived::hash_node((*this)[table[slot]]));
|
||||
if (((slot - home) & mask) >= ((slot - hole) & mask)) {
|
||||
table[hole] = table[slot];
|
||||
hole = slot;
|
||||
}
|
||||
}
|
||||
table[hole] = Ref();
|
||||
}
|
||||
|
||||
template<typename Derived, typename Node, typename Ref>
|
||||
void HashConsPool<Derived, Node, Ref>::grow_index() {
|
||||
std::vector<Ref> old(table.size() * 2, Ref());
|
||||
std::swap(old, table);
|
||||
for (Ref ref : old)
|
||||
if (ref != Ref())
|
||||
index_insert(ref);
|
||||
}
|
||||
|
||||
template<typename Derived, typename Node, typename Ref>
|
||||
Ref HashConsPool<Derived, Node, Ref>::add_inner(Node t) {
|
||||
Ref ref;
|
||||
if (!free_list.empty()) {
|
||||
size_t idx = free_list.back();
|
||||
free_list.pop_back();
|
||||
backing[idx] = std::move(t);
|
||||
ref = Ref(Derived::STATIC_COUNT + idx);
|
||||
} else {
|
||||
ref = Ref(Derived::STATIC_COUNT + backing.size());
|
||||
backing.push_back(std::move(t));
|
||||
}
|
||||
if ((Derived::STATIC_COUNT + size()) * 3 > table.size() * 2)
|
||||
grow_index();
|
||||
index_insert(ref);
|
||||
if (yosys_xtrace) {
|
||||
std::cout << "#X# add_inner added ";
|
||||
self()->dump(ref);
|
||||
std::cout << "\n";
|
||||
std::cout << "#X# as integer " << ref.raw() << "\n";
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
template<typename Derived, typename Node, typename Ref>
|
||||
template<typename Roots>
|
||||
size_t HashConsPool<Derived, Node, Ref>::gc(const Roots& roots) {
|
||||
pool<Ref> live;
|
||||
for (Ref ref : roots)
|
||||
mark_live(ref, live);
|
||||
size_t erased = 0;
|
||||
for (size_t idx = 0; idx < backing.size(); ++idx) {
|
||||
if (backing[idx].is_dead())
|
||||
continue;
|
||||
if (!live.count(Ref(Derived::STATIC_COUNT + idx))) {
|
||||
index_erase(Ref(Derived::STATIC_COUNT + idx));
|
||||
free_list.push_back(idx);
|
||||
backing[idx] = Node{};
|
||||
erased++;
|
||||
}
|
||||
}
|
||||
// TODO something like YOSYS_SORT_ID_FREE_LIST to make it optional?
|
||||
std::sort(free_list.begin(), free_list.end(), std::greater<size_t>());
|
||||
return erased;
|
||||
}
|
||||
|
||||
template<typename Derived, typename Node, typename Ref>
|
||||
void HashConsPool<Derived, Node, Ref>::mark_live(Ref ref, pool<Ref>& live) const {
|
||||
ref = ref.untag();
|
||||
if (ref == Ref() || is_static(ref) || !live.insert(ref).second)
|
||||
return;
|
||||
Derived::for_each_child((*this)[ref], [&](Ref child) { mark_live(child, live); });
|
||||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
@@ -1,8 +1,11 @@
|
||||
#include "kernel/twine.h"
|
||||
#include "kernel/hashcons_impl.h"
|
||||
#include "kernel/log.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
template struct HashConsPool<TwinePool, TwineNode, IdString>;
|
||||
|
||||
std::vector<TwineNode> StaticTwines::nodes_;
|
||||
|
||||
void StaticTwines::init() {
|
||||
@@ -185,6 +188,12 @@ const TwineNode& TwinePool::operator[](IdString ref) const {
|
||||
return HashConsPool::operator[](ref);
|
||||
}
|
||||
|
||||
size_t TwinePool::gc(pool<IdString>& roots) {
|
||||
for (auto &it : auto_prefixes)
|
||||
roots.insert(it.second);
|
||||
return HashConsPool::gc(roots);
|
||||
}
|
||||
|
||||
const TwineNode& TwinePool::static_node(size_t idx) { return StaticTwines::node(idx); }
|
||||
void TwinePool::check_ready() { log_assert(StaticTwines::ready()); }
|
||||
|
||||
|
||||
+1
-6
@@ -359,12 +359,7 @@ struct TwinePool : HashConsPool<TwinePool, TwineNode, IdString> {
|
||||
f(t.prefix());
|
||||
}
|
||||
|
||||
template<typename Roots>
|
||||
size_t gc(Roots& roots) {
|
||||
for (auto &it : auto_prefixes)
|
||||
roots.insert(it.second);
|
||||
return HashConsPool::gc(roots);
|
||||
}
|
||||
size_t gc(pool<IdString>& roots);
|
||||
|
||||
void dump(IdString ref, std::ostream& os = std::cout) const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user