From d071489ab1596b513a222ddc52c0b5e84f2eb0e9 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 1 Oct 2024 15:12:03 +0200 Subject: [PATCH 01/26] hashlib: redo interface for flexibility --- backends/cxxrtl/cxxrtl_backend.cc | 26 +-- examples/cxx-api/scopeinfo_example.cc | 2 +- frontends/ast/ast.h | 2 +- frontends/verific/verific.cc | 16 +- frontends/verific/verific.h | 4 +- frontends/verific/verificsva.cc | 2 +- kernel/bitpattern.h | 11 +- kernel/cellaigs.cc | 17 +- kernel/cellaigs.h | 4 +- kernel/drivertools.h | 222 +++++++++++++------- kernel/functional.h | 8 +- kernel/hashlib.h | 285 +++++++++++++++----------- kernel/log.h | 12 +- kernel/modtools.h | 20 +- kernel/rtlil.cc | 14 +- kernel/rtlil.h | 66 +++--- kernel/scopeinfo.h | 2 +- kernel/sigtools.h | 12 +- kernel/timinginfo.h | 12 +- kernel/utils.h | 12 +- kernel/yosys_common.h | 51 ++--- kernel/yw.h | 2 +- passes/cmds/dft_tag.cc | 2 +- passes/cmds/example_dt.cc | 6 +- passes/cmds/viz.cc | 38 ++-- passes/equiv/equiv_struct.cc | 10 +- passes/proc/proc_dlatch.cc | 9 +- passes/proc/proc_mux.cc | 8 +- passes/sat/mutate.cc | 2 +- passes/sat/recover_names.cc | 12 +- passes/sat/sim.cc | 2 +- passes/techmap/alumacc.cc | 6 +- passes/techmap/clockgate.cc | 5 +- passes/techmap/flowmap.cc | 6 +- techlibs/quicklogic/ql_dsp_simd.cc | 2 +- 35 files changed, 533 insertions(+), 377 deletions(-) diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index b72caf119c3..931454adaa1 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -47,7 +47,7 @@ struct Scheduler { struct Vertex { T *data; Vertex *prev, *next; - pool preds, succs; + pool preds, succs; Vertex() : data(NULL), prev(this), next(this) {} Vertex(T *data) : data(data), prev(NULL), next(NULL) {} @@ -300,10 +300,10 @@ struct FlowGraph { }; std::vector nodes; - dict> wire_comb_defs, wire_sync_defs, wire_uses; - dict, hash_ptr_ops> node_comb_defs, node_sync_defs, node_uses; + dict> wire_comb_defs, wire_sync_defs, wire_uses; + dict> node_comb_defs, node_sync_defs, node_uses; dict wire_def_inlinable; - dict> wire_use_inlinable; + dict> wire_use_inlinable; dict bit_has_state; ~FlowGraph() @@ -365,7 +365,7 @@ struct FlowGraph { return false; } - bool is_inlinable(const RTLIL::Wire *wire, const pool &nodes) const + bool is_inlinable(const RTLIL::Wire *wire, const pool &nodes) const { // Can the wire be inlined, knowing that the given nodes are reachable? if (nodes.size() != 1) @@ -3080,7 +3080,7 @@ struct CxxrtlWorker { // without feedback arcs can generally be evaluated in a single pass, i.e. it always requires only // a single delta cycle. Scheduler scheduler; - dict::Vertex*, hash_ptr_ops> node_vertex_map; + dict::Vertex*> node_vertex_map; for (auto node : flow.nodes) node_vertex_map[node] = scheduler.add(node); for (auto node_comb_def : flow.node_comb_defs) { @@ -3095,7 +3095,7 @@ struct CxxrtlWorker { // Find out whether the order includes any feedback arcs. std::vector node_order; - pool evaluated_nodes; + pool evaluated_nodes; pool feedback_wires; for (auto vertex : scheduler.schedule()) { auto node = vertex->data; @@ -3139,7 +3139,7 @@ struct CxxrtlWorker { } // Discover nodes reachable from primary outputs (i.e. members) and collect reachable wire users. - pool worklist; + pool worklist; for (auto node : flow.nodes) { if (node->type == FlowGraph::Node::Type::CELL_EVAL && !is_internal_cell(node->cell->type)) worklist.insert(node); // node evaluates a submodule @@ -3159,8 +3159,8 @@ struct CxxrtlWorker { worklist.insert(node); // node drives public wires } } - dict> live_wires; - pool live_nodes; + dict> live_wires; + pool live_nodes; while (!worklist.empty()) { auto node = worklist.pop(); live_nodes.insert(node); @@ -3290,15 +3290,15 @@ struct CxxrtlWorker { // Discover nodes reachable from primary outputs (i.e. outlines) up until primary inputs (i.e. members) // and collect reachable wire users. - pool worklist; + pool worklist; for (auto node : flow.nodes) { if (flow.node_comb_defs.count(node)) for (auto wire : flow.node_comb_defs[node]) if (debug_wire_types[wire].is_outline()) worklist.insert(node); // node drives outline } - dict> debug_live_wires; - pool debug_live_nodes; + dict> debug_live_wires; + pool debug_live_nodes; while (!worklist.empty()) { auto node = worklist.pop(); debug_live_nodes.insert(node); diff --git a/examples/cxx-api/scopeinfo_example.cc b/examples/cxx-api/scopeinfo_example.cc index f163dff9eee..0882ba80484 100644 --- a/examples/cxx-api/scopeinfo_example.cc +++ b/examples/cxx-api/scopeinfo_example.cc @@ -90,7 +90,7 @@ struct ScopeinfoExamplePass : public Pass { // Shuffle wires so this example produces more interesting outputs std::sort(wires.begin(), wires.end(), [](Wire *a, Wire *b) { - return mkhash_xorshift(a->name.hash() * 0x2c9277b5) < mkhash_xorshift(b->name.hash() * 0x2c9277b5); + return mkhash_xorshift(run_hash(a->name) * 0x2c9277b5) < mkhash_xorshift(run_hash(b->name) * 0x2c9277b5); }); ModuleHdlnameIndex index(module); diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index bdff015e3f4..1a72e62850e 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -177,7 +177,7 @@ namespace AST { // for dict<> and pool<> unsigned int hashidx_; - unsigned int hash() const { return hashidx_; } + Hasher hash_acc(Hasher h) const { h.acc(hashidx_); return h; } // this nodes type AstNodeType type; diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index d39030c2d0d..8f1b07b100e 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -619,7 +619,7 @@ RTLIL::SigSpec VerificImporter::operatorInportCase(Instance *inst, const char *p } } -RTLIL::SigSpec VerificImporter::operatorOutput(Instance *inst, const pool *any_all_nets) +RTLIL::SigSpec VerificImporter::operatorOutput(Instance *inst, const pool *any_all_nets) { RTLIL::SigSpec sig; RTLIL::Wire *dummy_wire = NULL; @@ -1576,9 +1576,9 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma module->fixup_ports(); - dict init_nets; - pool anyconst_nets, anyseq_nets; - pool allconst_nets, allseq_nets; + dict init_nets; + pool anyconst_nets, anyseq_nets; + pool allconst_nets, allseq_nets; any_all_nets.clear(); FOREACH_NET_OF_NETLIST(nl, mi, net) @@ -1841,10 +1841,10 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma module->connect(net_map_at(net), module->Anyseq(new_verific_id(net))); #ifdef VERIFIC_SYSTEMVERILOG_SUPPORT - pool sva_asserts; - pool sva_assumes; - pool sva_covers; - pool sva_triggers; + pool sva_asserts; + pool sva_assumes; + pool sva_covers; + pool sva_triggers; #endif pool past_ffs; diff --git a/frontends/verific/verific.h b/frontends/verific/verific.h index 3c77dd7c3b9..4e9c7a30598 100644 --- a/frontends/verific/verific.h +++ b/frontends/verific/verific.h @@ -71,7 +71,7 @@ struct VerificImporter std::map net_map; std::map sva_posedge_map; - pool any_all_nets; + pool any_all_nets; bool mode_gates, mode_keep, mode_nosva, mode_names, mode_verific; bool mode_autocover, mode_fullinit; @@ -89,7 +89,7 @@ struct VerificImporter RTLIL::SigSpec operatorInput2(Verific::Instance *inst); RTLIL::SigSpec operatorInport(Verific::Instance *inst, const char *portname); RTLIL::SigSpec operatorInportCase(Verific::Instance *inst, const char *portname); - RTLIL::SigSpec operatorOutput(Verific::Instance *inst, const pool *any_all_nets = nullptr); + RTLIL::SigSpec operatorOutput(Verific::Instance *inst, const pool *any_all_nets = nullptr); bool import_netlist_instance_gates(Verific::Instance *inst, RTLIL::IdString inst_name); bool import_netlist_instance_cells(Verific::Instance *inst, RTLIL::IdString inst_name); diff --git a/frontends/verific/verificsva.cc b/frontends/verific/verificsva.cc index ef8247e83df..860d3c16630 100644 --- a/frontends/verific/verificsva.cc +++ b/frontends/verific/verificsva.cc @@ -1051,7 +1051,7 @@ struct VerificSvaImporter msg.c_str(), inst->View()->Owner()->Name(), inst->Name()), inst->Linefile()); } - dict check_expression_cache; + dict check_expression_cache; bool check_expression(Net *net, bool raise_error = false) { diff --git a/kernel/bitpattern.h b/kernel/bitpattern.h index c1ceac14ca8..3814f4672b2 100644 --- a/kernel/bitpattern.h +++ b/kernel/bitpattern.h @@ -30,7 +30,7 @@ struct BitPatternPool int width; struct bits_t { std::vector 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>::hash(bitdata); - return cached_hash; + cached_hash = run_hash(bitdata); + h.acc(cached_hash); + return h; } }; pool database; diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc index de0a4939430..81b486c79f8 100644 --- a/kernel/cellaigs.cc +++ b/kernel/cellaigs.cc @@ -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::hash(name); + h.acc(name); + return h; } struct AigMaker diff --git a/kernel/cellaigs.h b/kernel/cellaigs.h index 8f6d69ba62b..bdb8b3c073c 100644 --- a/kernel/cellaigs.h +++ b/kernel/cellaigs.h @@ -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 diff --git a/kernel/drivertools.h b/kernel/drivertools.h index 8929c342627..fdead5c36e8 100644 --- a/kernel/drivertools.h +++ b/kernel/drivertools.h @@ -74,10 +74,8 @@ struct DriveBitWire return offset < other.offset; } - unsigned int hash() const - { - return mkhash_add(wire->name.hash(), offset); - } + Hasher hash_acc(Hasher h) const; + operator SigBit() const { @@ -107,10 +105,8 @@ struct DriveBitPort return offset < other.offset; } - unsigned int hash() const - { - return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset); - } + Hasher hash_acc(Hasher h) const; + }; @@ -133,10 +129,7 @@ struct DriveBitMarker return offset < other.offset; } - unsigned int hash() const - { - return mkhash_add(marker, offset); - } + Hasher hash_acc(Hasher h) const; }; @@ -171,10 +164,7 @@ struct DriveBitMultiple return multiple_ == other.multiple_; } - unsigned int hash() const - { - return multiple_.hash(); - } + Hasher hash_acc(Hasher h) const; }; struct DriveBit @@ -362,35 +352,7 @@ struct DriveBit return *this; } - unsigned int hash() const - { - unsigned int inner = 0; - switch (type_) - { - case DriveType::NONE: - inner = 0; - break; - case DriveType::CONSTANT: - inner = constant_; - break; - case DriveType::WIRE: - inner = wire_.hash(); - break; - case DriveType::PORT: - inner = port_.hash(); - break; - case DriveType::MARKER: - inner = marker_.hash(); - break; - case DriveType::MULTIPLE: - inner = multiple_.hash(); - break; - default: - log_abort(); - break; - } - return mkhash((unsigned int)type_, inner); - } + Hasher hash_acc(Hasher h) const; bool operator==(const DriveBit &other) const { @@ -511,10 +473,7 @@ struct DriveChunkWire return offset < other.offset; } - unsigned int hash() const - { - return mkhash_add(mkhash(wire->name.hash(), width), offset); - } + Hasher hash_acc(Hasher h) const; explicit operator SigChunk() const { @@ -572,10 +531,7 @@ struct DriveChunkPort return offset < other.offset; } - unsigned int hash() const - { - return mkhash_add(mkhash(mkhash(cell->name.hash(), port.hash()), width), offset); - } + Hasher hash_acc(Hasher h) const; }; @@ -616,10 +572,7 @@ struct DriveChunkMarker return offset < other.offset; } - unsigned int hash() const - { - return mkhash_add(mkhash(marker, width), offset); - } + Hasher hash_acc(Hasher h) const; }; struct DriveChunkMultiple @@ -659,10 +612,7 @@ struct DriveChunkMultiple return false; // TODO implement, canonicalize order } - unsigned int hash() const - { - return mkhash(width_, multiple_.hash()); - } + Hasher hash_acc(Hasher h) const; }; struct DriveChunk @@ -913,6 +863,7 @@ struct DriveChunk bool try_append(DriveBit const &bit); bool try_append(DriveChunk const &chunk); +<<<<<<< HEAD unsigned int hash() const { unsigned int inner = 0; @@ -942,6 +893,9 @@ struct DriveChunk } return mkhash((unsigned int)type_, inner); } +======= + Hasher hash_acc(Hasher h) const; +>>>>>>> 898d04260 (hashlib: redo interface for flexibility) bool operator==(const DriveChunk &other) const { @@ -1144,17 +1098,19 @@ struct DriveSpec 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>().hash(chunks_); - hash_ |= (hash_ == 0); - return hash_; + that->hash_ = run_hash(chunks_); + that->hash_ |= (that->hash_ == 0); } + Hasher hash_acc(Hasher h) const; + 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(); } @@ -1187,7 +1143,8 @@ struct DriverMap 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; }; // Essentially a dict> but using less memory // and fewer allocations @@ -1333,6 +1290,133 @@ struct DriverMap } }; +inline Hasher DriveBitWire::hash_acc(Hasher h) const +{ + h.acc(wire->name); + h.acc(offset); + return h; +} + +inline Hasher DriveBitPort::hash_acc(Hasher h) const +{ + h.acc(cell->name); + h.acc(port); + h.acc(offset); + return h; +} + +inline Hasher DriveBitMarker::hash_acc(Hasher h) const +{ + h.acc(marker); + h.acc(offset); + return h; +} + +inline Hasher DriveBitMultiple::hash_acc(Hasher h) const +{ + h.acc(multiple_); + return h; +} + +inline Hasher DriveBit::hash_acc(Hasher h) const +{ + switch (type_) { + case DriveType::NONE: + h.acc(0); + break; + case DriveType::CONSTANT: + h.acc(constant_); + break; + case DriveType::WIRE: + h.acc(wire_); + break; + case DriveType::PORT: + h.acc(port_); + break; + case DriveType::MARKER: + h.acc(marker_); + break; + case DriveType::MULTIPLE: + h.acc(multiple_); + break; + } + h.acc(type_); + return h; +} + +inline Hasher DriveChunkWire::hash_acc(Hasher h) const +{ + h.acc(wire->name); + h.acc(width); + h.acc(offset); + return h; +} + +inline Hasher DriveChunkPort::hash_acc(Hasher h) const +{ + h.acc(cell->name); + h.acc(port); + h.acc(width); + h.acc(offset); + return h; +} + +inline Hasher DriveChunkMarker::hash_acc(Hasher h) const +{ + h.acc(marker); + h.acc(width); + h.acc(offset); + return h; +} + +inline Hasher DriveChunkMultiple::hash_acc(Hasher h) const +{ + h.acc(width_); + h.acc(multiple_); + return h; +} + +inline Hasher DriveChunk::hash_acc(Hasher h) const +{ + switch (type_) { + case DriveType::NONE: + h.acc(0); + break; + case DriveType::CONSTANT: + h.acc(constant_); + break; + case DriveType::WIRE: + h.acc(wire_); + break; + case DriveType::PORT: + h.acc(port_); + break; + case DriveType::MARKER: + h.acc(marker_); + break; + case DriveType::MULTIPLE: + h.acc(multiple_); + break; + } + h.acc(type_); + return h; +} + +inline Hasher DriveSpec::hash_acc(Hasher h) const +{ + if (hash_ == 0) + updhash(); + + h.acc(hash_); + return h; +} + +inline Hasher DriverMap::DriveBitId::hash_acc(Hasher h) const +{ + h.acc(id); + return h; +} + YOSYS_NAMESPACE_END #endif diff --git a/kernel/functional.h b/kernel/functional.h index 61b303e0b48..b80c77be45b 100644 --- a/kernel/functional.h +++ b/kernel/functional.h @@ -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(_extra); } std::pair as_idstring_pair() const { return std::get>(_extra); } int as_int() const { return std::get(_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; diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 859115829d2..21e4e155b02 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -17,27 +17,47 @@ #include #include #include - +#include #include 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 +struct hash_ops; inline unsigned int mkhash_xorshift(unsigned int a) { if (sizeof(a) == 4) { @@ -53,62 +73,76 @@ inline unsigned int mkhash_xorshift(unsigned int a) { return a; } -template 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(); - } -}; +class Hasher { + public: //TODO + using hash_t = uint32_t; -struct hash_int_ops { - template - static inline bool cmp(T a, T b) { - return a == b; + Hasher() { + // traditionally 5381 is used as starting value for the djb2 hash + state = 5381; } -}; -template<> struct hash_ops : hash_int_ops -{ - static inline unsigned int hash(bool a) { - return a ? 1 : 0; + 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; } -}; -template<> struct hash_ops : hash_int_ops -{ - static inline unsigned int hash(int32_t a) { - return a; + public: + void hash32(uint32_t i) { + state = mkhash(i, state); + return; } -}; -template<> struct hash_ops : hash_int_ops -{ - static inline unsigned int hash(int64_t a) { - return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); + void hash64(uint64_t i) { + state = mkhash((uint32_t)(i % (1ULL << 32ULL)), state); + state = mkhash((uint32_t)(i >> 32ULL), state); + return; } -}; -template<> struct hash_ops : hash_int_ops -{ - static inline unsigned int hash(uint32_t a) { - return a; + hash_t yield() { + return (hash_t)state; } -}; -template<> struct hash_ops : hash_int_ops -{ - static inline unsigned int hash(uint64_t a) { - return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); + + template + void acc(T t) { + *this = hash_ops::hash_acc(t, *this); + } + + void commutative_acc(uint32_t t) { + state ^= t; } + }; +#endif -template<> struct hash_ops { - static inline bool cmp(const std::string &a, const std::string &b) { +template +struct hash_ops { + static inline bool cmp(const T &a, const T &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) { + h.hash32(a ? 1 : 0); + return h; + } else if constexpr (std::is_integral_v) { + 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) { + using u_type = std::underlying_type_t; + return hash_ops::hash_acc((u_type) a, h); + } else if constexpr (std::is_pointer_v) { + return hash_ops::hash_acc((uintptr_t) a, h); + } else if constexpr (std::is_same_v) { + for (auto c : a) + h.hash32(c); + return h; + } else { + return a.hash_acc(h); + } } }; @@ -116,8 +150,10 @@ template struct hash_ops> { static inline bool cmp(std::pair a, std::pair b) { return a == b; } - static inline unsigned int hash(std::pair a) { - return mkhash(hash_ops

::hash(a.first), hash_ops::hash(a.second)); + static inline Hasher hash_acc(std::pair a, Hasher h) { + h = hash_ops

::hash_acc(a.first, h); + h = hash_ops::hash_acc(a.second, h); + return h; } }; @@ -126,13 +162,15 @@ template struct hash_ops> { return a == b; } template - static inline typename std::enable_if::type hash(std::tuple) { - return mkhash_init; + static inline typename std::enable_if::type hash_acc(std::tuple, Hasher h) { + return h; } template - static inline typename std::enable_if::type hash(std::tuple a) { + static inline typename std::enable_if::type hash_acc(std::tuple a, Hasher h) { typedef hash_ops>::type> element_ops_t; - return mkhash(hash(a), element_ops_t::hash(std::get(a))); + h = hash_acc(a, h); + h = element_ops_t::hash_acc(std::get(a), h); + return h; } }; @@ -140,10 +178,10 @@ template struct hash_ops> { static inline bool cmp(std::vector a, std::vector b) { return a == b; } - static inline unsigned int hash(std::vector a) { - unsigned int h = mkhash_init; + static inline Hasher hash_acc(std::vector a, Hasher h) { + h.acc(a.size()); for (auto k : a) - h = mkhash(h, hash_ops::hash(k)); + h.acc(k); return h; } }; @@ -155,20 +193,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 : 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::hash_acc((uintptr_t)a, h); } }; @@ -177,22 +216,36 @@ struct hash_obj_ops { return a == b; } template - 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 -inline unsigned int mkhash(const T &v) { - return hash_ops().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 { 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; } }; @@ -200,9 +253,10 @@ template struct hash_ops> { static inline bool cmp(std::variant a, std::variant b) { return a == b; } - static inline unsigned int hash(std::variant 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 a, Hasher h) { + std::visit([& h](const auto &v) { h.acc(v); }, a); + h.acc(a.index()); + return h; } }; @@ -210,11 +264,12 @@ template struct hash_ops> { static inline bool cmp(std::optional a, std::optional b) { return a == b; } - static inline unsigned int hash(std::optional a) { + static inline Hasher hash_acc(std::optional a, Hasher h) { if(a.has_value()) - return mkhash(*a); + h.acc(*a); else - return 0; + h.acc(0); + return h; } }; @@ -246,14 +301,13 @@ inline int hashtable_size(int min_size) throw std::length_error("hash table exceeded maximum size."); } -template> class dict; -template> class idict; -template> class pool; -template> class mfp; +template class dict; +template class idict; +template class pool; +template class mfp; -template -class dict -{ +template +class dict { struct entry_t { std::pair udata; @@ -267,7 +321,7 @@ class dict std::vector hashtable; std::vector entries; - OPS ops; + hash_ops ops; #ifdef NDEBUG static inline void do_assert(bool) { } @@ -279,9 +333,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(key) % (unsigned int)(hashtable.size()); return hash; } @@ -683,11 +737,13 @@ class dict return !operator==(other); } - unsigned int hash() const { - unsigned int h = mkhash_init; - for (auto &entry : entries) { - h ^= hash_ops::hash(entry.udata.first); - h ^= hash_ops::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; } @@ -706,10 +762,10 @@ class dict const_iterator end() const { return const_iterator(nullptr, -1); } }; -template +template class pool { - template friend class idict; + template friend class idict; protected: struct entry_t @@ -724,7 +780,7 @@ class pool std::vector hashtable; std::vector entries; - OPS ops; + hash_ops ops; #ifdef NDEBUG static inline void do_assert(bool) { } @@ -736,9 +792,9 @@ class pool 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(key) % (unsigned int)(hashtable.size()); return hash; } @@ -1051,11 +1107,12 @@ class pool 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); } @@ -1072,10 +1129,10 @@ class pool const_iterator end() const { return const_iterator(nullptr, -1); } }; -template +template class idict { - pool database; + pool database; public: class const_iterator @@ -1169,14 +1226,14 @@ class idict * mfp stands for "merge, find, promote" * i-prefixed methods operate on indices in parents */ -template +template class mfp { - mutable idict database; + mutable idict database; mutable std::vector parents; public: - typedef typename idict::const_iterator const_iterator; + typedef typename idict::const_iterator const_iterator; constexpr mfp() { diff --git a/kernel/log.h b/kernel/log.h index 4b90cf9dceb..e26ef072cbc 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -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 static inline void log_dump_val_worker(dict &v); -template static inline void log_dump_val_worker(pool &v); +template static inline void log_dump_val_worker(dict &v); +template static inline void log_dump_val_worker(pool &v); template static inline void log_dump_val_worker(std::vector &v); template static inline void log_dump_val_worker(T *ptr); -template -static inline void log_dump_val_worker(dict &v) { +template +static inline void log_dump_val_worker(dict &v) { log("{"); bool first = true; for (auto &it : v) { @@ -382,8 +382,8 @@ static inline void log_dump_val_worker(dict &v) { log(" }"); } -template -static inline void log_dump_val_worker(pool &v) { +template +static inline void log_dump_val_worker(pool &v) { log("{"); bool first = true; for (auto &it : v) { diff --git a/kernel/modtools.h b/kernel/modtools.h index 34a23b37981..1afa0ad502a 100644 --- a/kernel/modtools.h +++ b/kernel/modtools.h @@ -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 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]); diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index b279cce6e15..65510362e6d 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -35,7 +35,7 @@ YOSYS_NAMESPACE_BEGIN bool RTLIL::IdString::destruct_guard_ok = false; RTLIL::IdString::destruct_guard_t RTLIL::IdString::destruct_guard; std::vector RTLIL::IdString::global_id_storage_; -dict RTLIL::IdString::global_id_index_; +dict RTLIL::IdString::global_id_index_; #ifndef YOSYS_NO_IDS_REFCNT std::vector RTLIL::IdString::global_refcount_storage_; std::vector RTLIL::IdString::global_free_idx_list_; @@ -4476,17 +4476,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; } diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 6d3558621c1..a1f8668d056 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -95,7 +95,7 @@ namespace RTLIL } destruct_guard; static std::vector global_id_storage_; - static dict global_id_index_; + static dict global_id_index_; #ifndef YOSYS_NO_IDS_REFCNT static std::vector global_refcount_storage_; static std::vector global_free_idx_list_; @@ -360,8 +360,8 @@ namespace RTLIL *this = IdString(); } - unsigned int hash() const { - return index_; + Hasher hash_acc(Hasher h) const { + return hash_ops::hash_acc(index_, h); } // The following is a helper key_compare class. Instead of for example std::set @@ -796,11 +796,10 @@ struct RTLIL::Const bv.resize(width, bv.empty() ? RTLIL::State::Sx : bv.back()); } - inline unsigned int hash() const { - unsigned int h = mkhash_init; - - for (State b : *this) - h = mkhash(h, b); + inline Hasher hash_acc(Hasher h) const { + // TODO hash size + for (auto b : *this) + h.acc(b); return h; } }; @@ -890,7 +889,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 @@ -931,7 +930,7 @@ struct RTLIL::SigSpec { private: int width_; - unsigned long hash_; + Hasher::hash_t hash_; std::vector chunks_; // LSB at index 0 std::vector bits_; // LSB at index 0 @@ -972,9 +971,10 @@ struct RTLIL::SigSpec SigSpec(const std::set &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 &chunks() const { pack(); return chunks_; } @@ -1083,7 +1083,7 @@ struct RTLIL::SigSpec operator std::vector() 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; @@ -1124,8 +1124,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; @@ -1147,8 +1147,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 monitors; dict scratchpad; @@ -1252,8 +1252,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); @@ -1607,8 +1607,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 @@ -1646,8 +1646,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(); @@ -1661,8 +1661,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 @@ -1771,8 +1771,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 @@ -1816,10 +1816,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 { diff --git a/kernel/scopeinfo.h b/kernel/scopeinfo.h index 8c6e99fc066..5d2e6d4b1c6 100644 --- a/kernel/scopeinfo.h +++ b/kernel/scopeinfo.h @@ -322,7 +322,7 @@ struct ModuleItem { Cell *cell() const { return type == Type::Cell ? static_cast(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::Cursor cursor ) { log("%p %s", cursor.target, log_id(cursor.scope_name)); } diff --git a/kernel/sigtools.h b/kernel/sigtools.h index 63f1b51ec84..f3779c37c4e 100644 --- a/kernel/sigtools.h +++ b/kernel/sigtools.h @@ -29,7 +29,11 @@ struct SigPool struct bitDef_t : public std::pair { bitDef_t() : std::pair(NULL, 0) { } bitDef_t(const RTLIL::SigBit &bit) : std::pair(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 bits; @@ -143,7 +147,11 @@ struct SigSet struct bitDef_t : public std::pair { bitDef_t() : std::pair(NULL, 0) { } bitDef_t(const RTLIL::SigBit &bit) : std::pair(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> bits; diff --git a/kernel/timinginfo.h b/kernel/timinginfo.h index 8eb7eb738ac..373615f59fc 100644 --- a/kernel/timinginfo.h +++ b/kernel/timinginfo.h @@ -36,7 +36,6 @@ 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); } std::optional get_connection(RTLIL::Cell *cell) { if (!cell->hasPort(name)) return {}; @@ -45,6 +44,11 @@ struct TimingInfo return {}; return port[offset]; } + Hasher hash_acc(Hasher h) const { + h.acc(name); + h.acc(offset); + return h; + } }; struct BitBit { @@ -52,7 +56,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 diff --git a/kernel/utils.h b/kernel/utils.h index 99f327db4cd..07edad07479 100644 --- a/kernel/utils.h +++ b/kernel/utils.h @@ -31,17 +31,17 @@ YOSYS_NAMESPACE_BEGIN // A map-like container, but you can save and restore the state // ------------------------------------------------ -template> +template struct stackmap { private: - std::vector> backup_state; - dict current_state; + std::vector> backup_state; + dict current_state; static T empty_tuple; public: stackmap() { } - stackmap(const dict &other) : current_state(other) { } + stackmap(const dict &other) : current_state(other) { } template void operator=(const Other &other) @@ -94,7 +94,7 @@ struct stackmap current_state.erase(k); } - const dict &stdmap() + const dict &stdmap() { return current_state; } @@ -128,7 +128,7 @@ struct stackmap // A simple class for topological sorting // ------------------------------------------------ -template , typename OPS = hash_ops> class TopoSort +template > class TopoSort { public: // We use this ordering of the edges in the adjacency matrix for diff --git a/kernel/yosys_common.h b/kernel/yosys_common.h index 29dcd58c55a..52f7f5f9686 100644 --- a/kernel/yosys_common.h +++ b/kernel/yosys_common.h @@ -153,6 +153,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 { @@ -163,22 +172,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::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; @@ -217,26 +216,6 @@ using RTLIL::State; using RTLIL::SigChunk; using RTLIL::SigSig; -namespace hashlib { - 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 {}; - 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 {}; -} - void memhasher_on(); void memhasher_off(); void memhasher_do(); @@ -347,10 +326,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 : hash_ops {}; -} - YOSYS_NAMESPACE_END diff --git a/kernel/yw.h b/kernel/yw.h index c2f5921b1d9..a4bae55152b 100644 --- a/kernel/yw.h +++ b/kernel/yw.h @@ -35,7 +35,7 @@ struct IdPath : public std::vector bool has_address() const { int tmp; return get_address(tmp); }; bool get_address(int &addr) const; - int hash() const { return hashlib::hash_ops>::hash(*this); } + Hasher hash_acc(Hasher h) const { h.acc(*this); return h; } }; struct WitnessHierarchyItem { diff --git a/passes/cmds/dft_tag.cc b/passes/cmds/dft_tag.cc index 8947570e791..0b1127a11a9 100644 --- a/passes/cmds/dft_tag.cc +++ b/passes/cmds/dft_tag.cc @@ -47,7 +47,7 @@ struct DftTagWorker { bool operator<(const tag_set &other) const { return index < other.index; } bool operator==(const tag_set &other) const { return index == other.index; } - unsigned int hash() const { return hash_ops::hash(index); } + Hasher hash_acc(Hasher h) const { h.acc(index); return h; } bool empty() const { return index == 0; } }; diff --git a/passes/cmds/example_dt.cc b/passes/cmds/example_dt.cc index 1912d7da172..97ce26327bb 100644 --- a/passes/cmds/example_dt.cc +++ b/passes/cmds/example_dt.cc @@ -52,8 +52,10 @@ struct ExampleDtPass : public Pass return name == other.name && parameters == other.parameters; } - unsigned int hash() const { - return mkhash(name.hash(), parameters.hash()); + Hasher hash_acc(Hasher h) const { + h.acc(name); + h.acc(parameters); + return h; } }; diff --git a/passes/cmds/viz.cc b/passes/cmds/viz.cc index 3655f3f491b..9dd68bd0087 100644 --- a/passes/cmds/viz.cc +++ b/passes/cmds/viz.cc @@ -70,13 +70,13 @@ struct GraphNode { pool names_; dict tags_; - pool upstream_; - pool downstream_; + pool upstream_; + pool downstream_; pool &names() { return get()->names_; } dict &tags() { return get()->tags_; } - pool &upstream() { return get()->upstream_; } - pool &downstream() { return get()->downstream_; } + pool &upstream() { return get()->upstream_; } + pool &downstream() { return get()->downstream_; } uint8_t tag(int index) { return tags().at(index, 0); @@ -154,8 +154,8 @@ struct Graph { nodes.push_back(n); n->index = GetSize(nodes); - pool new_upstream; - pool new_downstream; + pool new_upstream; + pool new_downstream; for (auto g : n->upstream()) { if (n != (g = g->get())) @@ -302,7 +302,7 @@ struct Graph { } } - pool excluded; + pool excluded; for (auto grp : config.groups) { @@ -348,7 +348,7 @@ struct Graph { excluded.insert(g->get()); dict cell_nodes; - dict> sig_users; + dict> sig_users; for (auto cell : module->selected_cells()) { auto g = new GraphNode; @@ -483,8 +483,8 @@ struct Graph { { header("Any nodes with identical connections"); - typedef pair, pool> node_conn_t; - dict> nodes_by_conn; + typedef pair, pool> node_conn_t; + dict> nodes_by_conn; for (auto g : term ? term_nodes : nonterm_nodes) { auto &entry = nodes_by_conn[node_conn_t(g->upstream(), g->downstream())]; for (auto n : entry) @@ -506,8 +506,8 @@ struct Graph { header("Sibblings with identical tags"); for (auto g : nonterm_nodes) { - auto process_conns = [&](const pool &stream) { - dict, pool> nodes_by_tags; + auto process_conns = [&](const pool &stream) { + dict, pool> nodes_by_tags; for (auto n : stream) { if (n->terminal) continue; std::vector key; @@ -556,7 +556,7 @@ struct Graph { if (!term) { header("Sibblings with similar tags (strict)"); for (auto g : nonterm_nodes) { - auto process_conns = [&](const pool &stream) { + auto process_conns = [&](const pool &stream) { std::vector nodes; for (auto n : stream) if (!n->terminal) nodes.push_back(n); @@ -585,7 +585,7 @@ struct Graph { if (!term) { header("Sibblings with similar tags (non-strict)"); for (auto g : nonterm_nodes) { - auto process_conns = [&](const pool &stream) { + auto process_conns = [&](const pool &stream) { std::vector nodes; for (auto n : stream) if (!n->terminal) nodes.push_back(n); @@ -603,7 +603,7 @@ struct Graph { { header("Any nodes with identical fan-in or fan-out"); - dict, pool> nodes_by_conn[2]; + dict, pool> nodes_by_conn[2]; for (auto g : term ? term_nodes : nonterm_nodes) { auto &up_entry = nodes_by_conn[0][g->upstream()]; auto &down_entry = nodes_by_conn[1][g->downstream()]; @@ -629,7 +629,7 @@ struct Graph { if (!term) { header("Sibblings with similar tags (lax)"); for (auto g : nonterm_nodes) { - auto process_conns = [&](const pool &stream) { + auto process_conns = [&](const pool &stream) { std::vector nodes; for (auto n : stream) if (!n->terminal) nodes.push_back(n); @@ -720,9 +720,9 @@ struct VizWorker fprintf(f, "digraph \"%s\" {\n", log_id(module)); fprintf(f, " rankdir = LR;\n"); - dict>, hash_ptr_ops> extra_lines; - dict bypass_nodes; - pool bypass_candidates; + dict>> extra_lines; + dict bypass_nodes; + pool bypass_candidates; auto bypass = [&](GraphNode *g, GraphNode *n) { log_assert(g->terminal); diff --git a/passes/equiv/equiv_struct.cc b/passes/equiv/equiv_struct.cc index 39604994a15..55b364971f7 100644 --- a/passes/equiv/equiv_struct.cc +++ b/passes/equiv/equiv_struct.cc @@ -46,11 +46,11 @@ struct EquivStructWorker parameters == other.parameters && port_sizes == other.port_sizes; } - unsigned int hash() const { - unsigned int h = mkhash_init; - h = mkhash(h, mkhash(type)); - h = mkhash(h, mkhash(parameters)); - h = mkhash(h, mkhash(connections)); + Hasher hash_acc(Hasher h) const { + h.acc(type); + h.acc(parameters); + h.acc(port_sizes); + h.acc(connections); return h; } }; diff --git a/passes/proc/proc_dlatch.cc b/passes/proc/proc_dlatch.cc index 5b392ce512b..5936502c09d 100644 --- a/passes/proc/proc_dlatch.cc +++ b/passes/proc/proc_dlatch.cc @@ -127,11 +127,10 @@ struct proc_dlatch_db_t return signal == other.signal && match == other.match && children == other.children; } - unsigned int hash() const { - unsigned int h = mkhash_init; - mkhash(h, signal.hash()); - mkhash(h, match.hash()); - for (auto i : children) mkhash(h, i); + Hasher hash_acc(Hasher h) const { + h.acc(signal); + h.acc(match); + h.acc(children); return h; } }; diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc index b209057fe86..2f539c960bf 100644 --- a/passes/proc/proc_mux.cc +++ b/passes/proc/proc_mux.cc @@ -108,8 +108,8 @@ struct SigSnippets struct SnippetSwCache { - dict, hash_ptr_ops> full_case_bits_cache; - dict, hash_ptr_ops> cache; + dict> full_case_bits_cache; + dict> cache; const SigSnippets *snippets; int current_snippet; @@ -318,7 +318,7 @@ const pool &get_full_case_bits(SnippetSwCache &swcache, RTLIL::SwitchRul return swcache.full_case_bits_cache.at(sw); } -RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, dict &swpara, +RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, dict &swpara, RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval, bool ifxmode) { RTLIL::SigSpec result = defval; @@ -421,7 +421,7 @@ void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc, bool ifxmode) swcache.snippets = &sigsnip; swcache.insert(&proc->root_case); - dict swpara; + dict swpara; int cnt = 0; for (int idx : sigsnip.snippets) diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index 02174be53dd..3075ef3f0c4 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -176,7 +176,7 @@ struct coverdb_t struct mutate_queue_t { - pool db; + pool db; mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) { mutate_t *m = nullptr; diff --git a/passes/sat/recover_names.cc b/passes/sat/recover_names.cc index 4870e2cac19..05ddf8e552e 100644 --- a/passes/sat/recover_names.cc +++ b/passes/sat/recover_names.cc @@ -46,9 +46,11 @@ struct IdBit { bool operator==(const IdBit &other) const { return name == other.name && bit == other.bit; }; bool operator!=(const IdBit &other) const { return name != other.name || bit != other.bit; }; - unsigned hash() const + Hasher hash_acc(Hasher h) const { - return mkhash_add(name.hash(), bit); + h.acc(name); + h.acc(bit); + return h; } IdString name; @@ -62,9 +64,11 @@ struct InvBit { bool operator==(const InvBit &other) const { return bit == other.bit && inverted == other.inverted; }; bool operator!=(const InvBit &other) const { return bit != other.bit || inverted != other.inverted; }; - unsigned hash() const + Hasher hash_acc(Hasher h) const { - return mkhash(bit.hash(), inverted); + h.acc(bit); + h.acc(inverted); + return h; } IdBit bit; diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index c3fa213f6e5..8fac93b98b5 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -161,7 +161,7 @@ struct SimInstance pool dirty_bits; pool dirty_cells; pool dirty_memories; - pool dirty_children; + pool dirty_children; struct ff_state_t { diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc index e4e70004c0f..05a3d17029f 100644 --- a/passes/techmap/alumacc.cc +++ b/passes/techmap/alumacc.cc @@ -111,7 +111,7 @@ struct AlumaccWorker dict bit_users; dict sig_macc; - dict> sig_alu; + dict> sig_alu; int macc_counter, alu_counter; AlumaccWorker(RTLIL::Module *module) : module(module), sigmap(module) @@ -226,7 +226,7 @@ struct AlumaccWorker { while (1) { - pool delete_nodes; + pool delete_nodes; for (auto &it : sig_macc) { @@ -278,7 +278,7 @@ struct AlumaccWorker void macc_to_alu() { - pool delete_nodes; + pool delete_nodes; for (auto &it : sig_macc) { diff --git a/passes/techmap/clockgate.cc b/passes/techmap/clockgate.cc index 44fdc7e47aa..79c1be7c134 100644 --- a/passes/techmap/clockgate.cc +++ b/passes/techmap/clockgate.cc @@ -233,10 +233,9 @@ struct ClockgatePass : public Pass { SigBit ce_bit; bool pol_clk; bool pol_ce; - unsigned int hash() const { + Hasher hash_acc(Hasher h) const { auto t = std::make_tuple(clk_bit, ce_bit, pol_clk, pol_ce); - unsigned int h = mkhash_init; - h = mkhash(h, hash_ops::hash(t)); + h.acc(t); return h; } bool operator==(const ClkNetInfo& other) const { diff --git a/passes/techmap/flowmap.cc b/passes/techmap/flowmap.cc index b5b95132364..b07097b9967 100644 --- a/passes/techmap/flowmap.cc +++ b/passes/techmap/flowmap.cc @@ -250,9 +250,11 @@ struct FlowGraph { return !(*this == other); } - unsigned int hash() const + Hasher hash_acc(Hasher h) const { - return hash_ops>::hash({node, is_bottom}); + std::pair p = {node, is_bottom}; + h.acc(p); + return h; } static NodePrime top(RTLIL::SigBit node) diff --git a/techlibs/quicklogic/ql_dsp_simd.cc b/techlibs/quicklogic/ql_dsp_simd.cc index b42823d8b10..bcbb290dfa8 100644 --- a/techlibs/quicklogic/ql_dsp_simd.cc +++ b/techlibs/quicklogic/ql_dsp_simd.cc @@ -53,7 +53,7 @@ struct QlDspSimdPass : public Pass { DspConfig(const DspConfig &ref) = default; DspConfig(DspConfig &&ref) = default; - unsigned int hash() const { return connections.hash(); } + Hasher hash_acc(Hasher h) const { h.acc(connections); return h; } bool operator==(const DspConfig &ref) const { return connections == ref.connections; } }; From 953508f6d208b17740f08cea673f2d4bacc292f2 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 1 Oct 2024 16:02:41 +0200 Subject: [PATCH 02/26] driver: add --hash-seed --- kernel/driver.cc | 7 +++++++ kernel/drivertools.h | 32 -------------------------------- kernel/hashlib.h | 9 ++++++++- kernel/scopeinfo.h | 7 +++++-- kernel/yosys.cc | 1 + 5 files changed, 21 insertions(+), 35 deletions(-) diff --git a/kernel/driver.cc b/kernel/driver.cc index 6565c472c2a..a3d85bd90e9 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -18,6 +18,7 @@ */ #include "kernel/yosys.h" +#include "kernel/hashlib.h" #include "libs/sha1/sha1.h" #include "libs/cxxopts/include/cxxopts.hpp" #include @@ -282,6 +283,8 @@ int main(int argc, char **argv) ("M,randomize-pointers", "will slightly randomize allocated pointer addresses. for debugging") ("autoidx", "start counting autoidx up from , similar effect to --hash-seed", cxxopts::value(), "") + ("hash-seed", "mix up hashing values with , for extreme optimization and testing", + cxxopts::value(), "") ("A,abort", "will call abort() at the end of the script. for debugging") ("x,experimental", "do not print warnings for the experimental ", cxxopts::value>(), "") @@ -437,6 +440,10 @@ int main(int argc, char **argv) int idx = result["autoidx"].as(); autoidx = idx; } + if (result.count("hash-seed")) { + int seed = result["hash-seed"].as(); + Hasher::set_fudge((Hasher::hash_t)seed); + } if (log_errfile == NULL) { log_files.push_back(stdout); diff --git a/kernel/drivertools.h b/kernel/drivertools.h index fdead5c36e8..0e7b872e4ba 100644 --- a/kernel/drivertools.h +++ b/kernel/drivertools.h @@ -863,39 +863,7 @@ struct DriveChunk bool try_append(DriveBit const &bit); bool try_append(DriveChunk const &chunk); -<<<<<<< HEAD - unsigned int hash() const - { - unsigned int inner = 0; - switch (type_) - { - case DriveType::NONE: - inner = 0; - break; - case DriveType::CONSTANT: - inner = constant_.hash(); - break; - case DriveType::WIRE: - inner = wire_.hash(); - break; - case DriveType::PORT: - inner = port_.hash(); - break; - case DriveType::MARKER: - inner = marker_.hash(); - break; - case DriveType::MULTIPLE: - inner = multiple_.hash(); - break; - default: - log_abort(); - break; - } - return mkhash((unsigned int)type_, inner); - } -======= Hasher hash_acc(Hasher h) const; ->>>>>>> 898d04260 (hashlib: redo interface for flexibility) bool operator==(const DriveChunk &other) const { diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 21e4e155b02..15c2c1afbd6 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -81,13 +81,20 @@ class Hasher { // traditionally 5381 is used as starting value for the djb2 hash state = 5381; } + static void set_fudge(uint32_t f) { + fudge = f; + } private: uint32_t state; + static uint32_t fudge; // The XOR version of DJB2 [[nodiscard]] static uint32_t mkhash(uint32_t a, uint32_t b) { - return ((a << 5) + a) ^ b; + uint32_t hash = ((a << 5) + a) ^ b; + if (fudge) + hash = fudge ^ mkhash_xorshift(hash); + return hash; } public: void hash32(uint32_t i) { diff --git a/kernel/scopeinfo.h b/kernel/scopeinfo.h index 5d2e6d4b1c6..fa550dab638 100644 --- a/kernel/scopeinfo.h +++ b/kernel/scopeinfo.h @@ -169,8 +169,11 @@ class IdTree return !(*this == other); } - int hash() const { - return mkhash(scope_name.hash(), hash_ptr_ops::hash(target)); + Hasher hash_acc(Hasher h) const + { + h.acc(scope_name); + h.acc(target); + return h; } bool valid() const { diff --git a/kernel/yosys.cc b/kernel/yosys.cc index bdd7303aa45..7cf60f068f1 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -93,6 +93,7 @@ std::set yosys_input_files, yosys_output_files; bool memhasher_active = false; uint32_t memhasher_rng = 123456; std::vector memhasher_store; +uint32_t Hasher::fudge = 0; std::string yosys_share_dirname; std::string yosys_abc_executable; From c10b3f57e1b08513d9d255ef84d0bf6b54c6badb Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Fri, 4 Oct 2024 13:20:15 +0200 Subject: [PATCH 03/26] abc: sort stats --- passes/techmap/abc.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 07f9ee45d82..cc37677ce21 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -1411,6 +1411,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin module->connect(conn); } + cell_stats.sort(); for (auto &it : cell_stats) log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second); int in_wires = 0, out_wires = 0; From db04788c1885389c1b177288c2ea33e0644f1d6a Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 9 Oct 2024 15:00:31 +0200 Subject: [PATCH 04/26] hashlib: fix pyosys --- kernel/hashlib.h | 7 ++++++- misc/py_wrap_generator.py | 28 ++++++++++++++++------------ 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 15c2c1afbd6..2e4c4917646 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -111,7 +111,12 @@ class Hasher { } template - void acc(T t) { + void acc(T&& t) { + *this = hash_ops>>::hash_acc(std::forward(t), *this); + } + + template + void acc(const T& t) { *this = hash_ops::hash_acc(t, *this); } diff --git a/misc/py_wrap_generator.py b/misc/py_wrap_generator.py index c62e624d2d2..03374c61019 100644 --- a/misc/py_wrap_generator.py +++ b/misc/py_wrap_generator.py @@ -855,7 +855,11 @@ def gen_decl(self, filename): if self.hash_id != None: text += "\n\t\tunsigned int get_hash_py()" text += "\n\t\t{" - text += "\n\t\t\treturn get_cpp_obj()->" + self.hash_id + ";" + suffix = f"->{self.hash_id}" if self.hash_id else f"->{self.hash_id}" + if self.hash_id == "": + text += f"\n\t\t\treturn run_hash(*(get_cpp_obj()));" + else: + text += f"\n\t\t\treturn run_hash(get_cpp_obj()->{self.hash_id});" text += "\n\t\t}" text += "\n\t};\n" @@ -956,7 +960,7 @@ def contains_default_constr(self): sources = [ Source("kernel/celltypes",[ - WClass("CellType", link_types.pointer, None, None, "type.hash()", True), + WClass("CellType", link_types.pointer, None, None, "type", True), WClass("CellTypes", link_types.pointer, None, None, None, True) ] ), @@ -970,23 +974,23 @@ def contains_default_constr(self): ] ), Source("kernel/rtlil",[ - WClass("IdString", link_types.ref_copy, None, "str()", "hash()"), - WClass("Const", link_types.ref_copy, None, "as_string()", "hash()"), + WClass("IdString", link_types.ref_copy, None, "str()", ""), + WClass("Const", link_types.ref_copy, None, "as_string()", ""), WClass("AttrObject", link_types.ref_copy, None, None, None), WClass("Selection", link_types.ref_copy, None, None, None), WClass("Monitor", link_types.derive, None, None, None), WClass("CaseRule",link_types.ref_copy, None, None, None, True), WClass("SwitchRule",link_types.ref_copy, None, None, None, True), WClass("SyncRule", link_types.ref_copy, None, None, None, True), - WClass("Process", link_types.ref_copy, None, "name.c_str()", "name.hash()"), + WClass("Process", link_types.ref_copy, None, "name.c_str()", "name"), WClass("SigChunk", link_types.ref_copy, None, None, None), - WClass("SigBit", link_types.ref_copy, None, None, "hash()"), - WClass("SigSpec", link_types.ref_copy, None, None, "hash()"), - WClass("Cell", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"), - WClass("Wire", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"), - WClass("Memory", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"), - WClass("Module", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"), - WClass("Design", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "hashidx_", "hash()") + WClass("SigBit", link_types.ref_copy, None, None, ""), + WClass("SigSpec", link_types.ref_copy, None, None, ""), + WClass("Cell", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", ""), + WClass("Wire", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", ""), + WClass("Memory", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", ""), + WClass("Module", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", ""), + WClass("Design", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "hashidx_", "") ] ), #Source("kernel/satgen",[ From c73c88033d42158a798c97c6bf3114d28e02e62b Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 15 Oct 2024 12:00:51 +0200 Subject: [PATCH 05/26] hashlib: only include in one place --- kernel/hashlib.h | 2 ++ kernel/yosys_common.h | 3 +-- passes/cmds/rename.cc | 1 - 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 2e4c4917646..b4d82f80ada 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -34,6 +34,8 @@ namespace hashlib { * 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. + * Never directly include kernel/hashlib.h in Yosys code. + * Instead include kernel/yosys_common.h * * The hash_ops type is now always left to its default value, derived * from templated functions through SFINAE. Providing custom ops is diff --git a/kernel/yosys_common.h b/kernel/yosys_common.h index 52f7f5f9686..9370de33078 100644 --- a/kernel/yosys_common.h +++ b/kernel/yosys_common.h @@ -134,8 +134,7 @@ YOSYS_NAMESPACE_BEGIN // Note: All headers included in hashlib.h must be included // outside of YOSYS_NAMESPACE before this or bad things will happen. #ifdef HASHLIB_H -# undef HASHLIB_H -# include "kernel/hashlib.h" +# error You've probably included hashlib.h under two namespace paths. Bad idea. #else # include "kernel/hashlib.h" # undef HASHLIB_H diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc index 3f8d807b36d..fe8b4a44498 100644 --- a/passes/cmds/rename.cc +++ b/passes/cmds/rename.cc @@ -20,7 +20,6 @@ #include "kernel/register.h" #include "kernel/rtlil.h" #include "kernel/log.h" -#include "kernel/hashlib.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN From b8738e2bd774726ac69490401989ea5a01d2d301 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Fri, 18 Oct 2024 12:34:25 +0200 Subject: [PATCH 06/26] hashlib: use hash_t across the board --- kernel/hashlib.h | 94 ++++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index b4d82f80ada..a1dffdaee44 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -83,7 +83,7 @@ class Hasher { // traditionally 5381 is used as starting value for the djb2 hash state = 5381; } - static void set_fudge(uint32_t f) { + static void set_fudge(hash_t f) { fudge = f; } @@ -108,6 +108,7 @@ class Hasher { state = mkhash((uint32_t)(i >> 32ULL), state); return; } + [[nodiscard]] hash_t yield() { return (hash_t)state; } @@ -241,6 +242,7 @@ struct hash_obj_ops { * desirable qualities of the hash function */ template +[[nodiscard]] Hasher::hash_t run_hash(const T& obj) { Hasher h; h.acc(obj); @@ -345,7 +347,7 @@ class dict { } #endif - int do_hash(const K &key) const + Hasher::hash_t do_hash(const K &key) const { Hasher::hash_t hash = 0; if (!hashtable.empty()) @@ -360,13 +362,13 @@ class dict { for (int i = 0; i < int(entries.size()); i++) { do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size())); - int hash = do_hash(entries[i].udata.first); + Hasher::hash_t hash = do_hash(entries[i].udata.first); entries[i].next = hashtable[hash]; hashtable[hash] = i; } } - int do_erase(int index, int hash) + int do_erase(int index, Hasher::hash_t hash) { do_assert(index < int(entries.size())); if (hashtable.empty() || index < 0) @@ -389,7 +391,7 @@ class dict { if (index != back_idx) { - int back_hash = do_hash(entries[back_idx].udata.first); + Hasher::hash_t back_hash = do_hash(entries[back_idx].udata.first); k = hashtable[back_hash]; do_assert(0 <= k && k < int(entries.size())); @@ -415,7 +417,7 @@ class dict { return 1; } - int do_lookup(const K &key, int &hash) const + int do_lookup(const K &key, Hasher::hash_t &hash) const { if (hashtable.empty()) return -1; @@ -435,7 +437,7 @@ class dict { return index; } - int do_insert(const K &key, int &hash) + int do_insert(const K &key, Hasher::hash_t &hash) { if (hashtable.empty()) { entries.emplace_back(std::pair(key, T()), -1); @@ -448,7 +450,7 @@ class dict { return entries.size() - 1; } - int do_insert(const std::pair &value, int &hash) + int do_insert(const std::pair &value, Hasher::hash_t &hash) { if (hashtable.empty()) { entries.emplace_back(value, -1); @@ -461,7 +463,7 @@ class dict { return entries.size() - 1; } - int do_insert(std::pair &&rvalue, int &hash) + int do_insert(std::pair &&rvalue, Hasher::hash_t &hash) { if (hashtable.empty()) { auto key = rvalue.first; @@ -573,7 +575,7 @@ class dict { std::pair insert(const K &key) { - int hash = do_hash(key); + Hasher::hash_t hash = do_hash(key); int i = do_lookup(key, hash); if (i >= 0) return std::pair(iterator(this, i), false); @@ -583,7 +585,7 @@ class dict { std::pair insert(const std::pair &value) { - int hash = do_hash(value.first); + Hasher::hash_t hash = do_hash(value.first); int i = do_lookup(value.first, hash); if (i >= 0) return std::pair(iterator(this, i), false); @@ -593,7 +595,7 @@ class dict { std::pair insert(std::pair &&rvalue) { - int hash = do_hash(rvalue.first); + Hasher::hash_t hash = do_hash(rvalue.first); int i = do_lookup(rvalue.first, hash); if (i >= 0) return std::pair(iterator(this, i), false); @@ -603,7 +605,7 @@ class dict { std::pair emplace(K const &key, T const &value) { - int hash = do_hash(key); + Hasher::hash_t hash = do_hash(key); int i = do_lookup(key, hash); if (i >= 0) return std::pair(iterator(this, i), false); @@ -613,7 +615,7 @@ class dict { std::pair emplace(K const &key, T &&rvalue) { - int hash = do_hash(key); + Hasher::hash_t hash = do_hash(key); int i = do_lookup(key, hash); if (i >= 0) return std::pair(iterator(this, i), false); @@ -623,7 +625,7 @@ class dict { std::pair emplace(K &&rkey, T const &value) { - int hash = do_hash(rkey); + Hasher::hash_t hash = do_hash(rkey); int i = do_lookup(rkey, hash); if (i >= 0) return std::pair(iterator(this, i), false); @@ -633,7 +635,7 @@ class dict { std::pair emplace(K &&rkey, T &&rvalue) { - int hash = do_hash(rkey); + Hasher::hash_t hash = do_hash(rkey); int i = do_lookup(rkey, hash); if (i >= 0) return std::pair(iterator(this, i), false); @@ -643,35 +645,35 @@ class dict { int erase(const K &key) { - int hash = do_hash(key); + Hasher::hash_t hash = do_hash(key); int index = do_lookup(key, hash); return do_erase(index, hash); } iterator erase(iterator it) { - int hash = do_hash(it->first); + Hasher::hash_t hash = do_hash(it->first); do_erase(it.index, hash); return ++it; } int count(const K &key) const { - int hash = do_hash(key); + Hasher::hash_t hash = do_hash(key); int i = do_lookup(key, hash); return i < 0 ? 0 : 1; } int count(const K &key, const_iterator it) const { - int hash = do_hash(key); + Hasher::hash_t hash = do_hash(key); int i = do_lookup(key, hash); return i < 0 || i > it.index ? 0 : 1; } iterator find(const K &key) { - int hash = do_hash(key); + Hasher::hash_t hash = do_hash(key); int i = do_lookup(key, hash); if (i < 0) return end(); @@ -680,7 +682,7 @@ class dict { const_iterator find(const K &key) const { - int hash = do_hash(key); + Hasher::hash_t hash = do_hash(key); int i = do_lookup(key, hash); if (i < 0) return end(); @@ -689,7 +691,7 @@ class dict { T& at(const K &key) { - int hash = do_hash(key); + Hasher::hash_t hash = do_hash(key); int i = do_lookup(key, hash); if (i < 0) throw std::out_of_range("dict::at()"); @@ -698,7 +700,7 @@ class dict { const T& at(const K &key) const { - int hash = do_hash(key); + Hasher::hash_t hash = do_hash(key); int i = do_lookup(key, hash); if (i < 0) throw std::out_of_range("dict::at()"); @@ -707,7 +709,7 @@ class dict { const T& at(const K &key, const T &defval) const { - int hash = do_hash(key); + Hasher::hash_t hash = do_hash(key); int i = do_lookup(key, hash); if (i < 0) return defval; @@ -716,7 +718,7 @@ class dict { T& operator[](const K &key) { - int hash = do_hash(key); + Hasher::hash_t hash = do_hash(key); int i = do_lookup(key, hash); if (i < 0) i = do_insert(std::pair(key, T()), hash); @@ -804,7 +806,7 @@ class pool } #endif - int do_hash(const K &key) const + Hasher::hash_t do_hash(const K &key) const { Hasher::hash_t hash = 0; if (!hashtable.empty()) @@ -819,13 +821,13 @@ class pool for (int i = 0; i < int(entries.size()); i++) { do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size())); - int hash = do_hash(entries[i].udata); + Hasher::hash_t hash = do_hash(entries[i].udata); entries[i].next = hashtable[hash]; hashtable[hash] = i; } } - int do_erase(int index, int hash) + int do_erase(int index, Hasher::hash_t hash) { do_assert(index < int(entries.size())); if (hashtable.empty() || index < 0) @@ -846,7 +848,7 @@ class pool if (index != back_idx) { - int back_hash = do_hash(entries[back_idx].udata); + Hasher::hash_t back_hash = do_hash(entries[back_idx].udata); k = hashtable[back_hash]; if (k == back_idx) { @@ -870,7 +872,7 @@ class pool return 1; } - int do_lookup(const K &key, int &hash) const + int do_lookup(const K &key, Hasher::hash_t &hash) const { if (hashtable.empty()) return -1; @@ -890,7 +892,7 @@ class pool return index; } - int do_insert(const K &value, int &hash) + int do_insert(const K &value, Hasher::hash_t &hash) { if (hashtable.empty()) { entries.emplace_back(value, -1); @@ -903,7 +905,7 @@ class pool return entries.size() - 1; } - int do_insert(K &&rvalue, int &hash) + int do_insert(K &&rvalue, Hasher::hash_t &hash) { if (hashtable.empty()) { entries.emplace_back(std::forward(rvalue), -1); @@ -1010,7 +1012,7 @@ class pool std::pair insert(const K &value) { - int hash = do_hash(value); + Hasher::hash_t hash = do_hash(value); int i = do_lookup(value, hash); if (i >= 0) return std::pair(iterator(this, i), false); @@ -1020,7 +1022,7 @@ class pool std::pair insert(K &&rvalue) { - int hash = do_hash(rvalue); + Hasher::hash_t hash = do_hash(rvalue); int i = do_lookup(rvalue, hash); if (i >= 0) return std::pair(iterator(this, i), false); @@ -1036,35 +1038,35 @@ class pool int erase(const K &key) { - int hash = do_hash(key); + Hasher::hash_t hash = do_hash(key); int index = do_lookup(key, hash); return do_erase(index, hash); } iterator erase(iterator it) { - int hash = do_hash(*it); + Hasher::hash_t hash = do_hash(*it); do_erase(it.index, hash); return ++it; } int count(const K &key) const { - int hash = do_hash(key); + Hasher::hash_t hash = do_hash(key); int i = do_lookup(key, hash); return i < 0 ? 0 : 1; } int count(const K &key, const_iterator it) const { - int hash = do_hash(key); + Hasher::hash_t hash = do_hash(key); int i = do_lookup(key, hash); return i < 0 || i > it.index ? 0 : 1; } iterator find(const K &key) { - int hash = do_hash(key); + Hasher::hash_t hash = do_hash(key); int i = do_lookup(key, hash); if (i < 0) return end(); @@ -1073,7 +1075,7 @@ class pool const_iterator find(const K &key) const { - int hash = do_hash(key); + Hasher::hash_t hash = do_hash(key); int i = do_lookup(key, hash); if (i < 0) return end(); @@ -1082,7 +1084,7 @@ class pool bool operator[](const K &key) { - int hash = do_hash(key); + Hasher::hash_t hash = do_hash(key); int i = do_lookup(key, hash); return i >= 0; } @@ -1176,7 +1178,7 @@ class idict int operator()(const K &key) { - int hash = database.do_hash(key); + Hasher::hash_t hash = database.do_hash(key); int i = database.do_lookup(key, hash); if (i < 0) i = database.do_insert(key, hash); @@ -1185,7 +1187,7 @@ class idict int at(const K &key) const { - int hash = database.do_hash(key); + Hasher::hash_t hash = database.do_hash(key); int i = database.do_lookup(key, hash); if (i < 0) throw std::out_of_range("idict::at()"); @@ -1194,7 +1196,7 @@ class idict int at(const K &key, int defval) const { - int hash = database.do_hash(key); + Hasher::hash_t hash = database.do_hash(key); int i = database.do_lookup(key, hash); if (i < 0) return defval; @@ -1203,7 +1205,7 @@ class idict int count(const K &key) const { - int hash = database.do_hash(key); + Hasher::hash_t hash = database.do_hash(key); int i = database.do_lookup(key, hash); return i < 0 ? 0 : 1; } From 582259f770e1ea8acf766375da2b8107912f73c1 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Fri, 18 Oct 2024 16:18:19 +0200 Subject: [PATCH 07/26] hashlib: hash_t can be set to 64-bit --- kernel/hashlib.h | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index a1dffdaee44..4ed1a5605b8 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -54,9 +54,9 @@ namespace hashlib { const int hashtable_size_trigger = 2; const int hashtable_size_factor = 3; -#define DJB2_BROKEN_SIZE +#define DJB2_32 + -#ifdef DJB2_BROKEN_SIZE template struct hash_ops; @@ -76,8 +76,13 @@ inline unsigned int mkhash_xorshift(unsigned int a) { } class Hasher { - public: //TODO + public: + #ifdef DJB2_32 using hash_t = uint32_t; + #endif + #ifdef DJB2_64 + using hash_t = uint64_t; + #endif Hasher() { // traditionally 5381 is used as starting value for the djb2 hash @@ -128,7 +133,6 @@ class Hasher { } }; -#endif template struct hash_ops { @@ -201,6 +205,17 @@ template struct hash_ops> { } }; +template struct hash_ops> { + static inline bool cmp(std::array a, std::array b) { + return a == b; + } + static inline Hasher hash_acc(std::array a, Hasher h) { + for (const auto& k : a) + h = hash_ops::hash_acc(k, h); + return h; + } +}; + struct hash_cstr_ops { static inline bool cmp(const char *a, const char *b) { for (int i = 0; a[i] || b[i]; i++) From 209ab6fb722de416f10f212b5b5633320d52c1f0 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Fri, 18 Oct 2024 22:59:27 +0200 Subject: [PATCH 08/26] hashlib: fudge always --- kernel/hashlib.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 4ed1a5605b8..13b53e38332 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -99,8 +99,7 @@ class Hasher { [[nodiscard]] static uint32_t mkhash(uint32_t a, uint32_t b) { uint32_t hash = ((a << 5) + a) ^ b; - if (fudge) - hash = fudge ^ mkhash_xorshift(hash); + hash = mkhash_xorshift(fudge ^ hash); return hash; } public: From c1af19fabc5fc108092c2c1d8094acc3b5ee73ab Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 30 Oct 2024 10:48:09 +0100 Subject: [PATCH 09/26] hashlib: don't xorshift in between upper and lower word --- kernel/hashlib.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 13b53e38332..33a1e04f89c 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -99,17 +99,18 @@ class Hasher { [[nodiscard]] static uint32_t mkhash(uint32_t a, uint32_t b) { uint32_t hash = ((a << 5) + a) ^ b; - hash = mkhash_xorshift(fudge ^ hash); return hash; } public: void hash32(uint32_t i) { state = mkhash(i, state); + state = mkhash_xorshift(fudge ^ state); return; } void hash64(uint64_t i) { state = mkhash((uint32_t)(i % (1ULL << 32ULL)), state); state = mkhash((uint32_t)(i >> 32ULL), state); + state = mkhash_xorshift(fudge ^ state); return; } [[nodiscard]] From 4d14399749a31cf18826548332a48c6418d5e7e0 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 30 Oct 2024 10:49:17 +0100 Subject: [PATCH 10/26] hashlib: allow forcing Hasher state, use it for IdString trivial hashing --- kernel/hashlib.h | 7 +++++++ kernel/rtlil.h | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 33a1e04f89c..aa9f43ff4d3 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -132,6 +132,13 @@ class Hasher { state ^= t; } + void force(hash_t new_state) { + state = new_state; + } + + bool is_new() const { + return state == Hasher().state; + } }; template diff --git a/kernel/rtlil.h b/kernel/rtlil.h index a1f8668d056..b048b1a4467 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -361,6 +361,12 @@ namespace RTLIL } Hasher hash_acc(Hasher h) const { + // If we're starting a hashing sequence, simply start with unhashed ID + if (h.is_new()) { + h.force((Hasher::hash_t) index_); + return h; + } + return hash_ops::hash_acc(index_, h); } From b7991ed1f5356de2b20da0434d4a85ff74ace732 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 30 Oct 2024 11:48:54 +0100 Subject: [PATCH 11/26] hashlib: prevent naive hashing of IdString when hashing SigBit --- kernel/rtlil.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index b048b1a4467..4f95504781c 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1824,8 +1824,10 @@ inline bool RTLIL::SigBit::operator!=(const RTLIL::SigBit &other) const { inline Hasher RTLIL::SigBit::hash_acc(Hasher h) const { if (wire) { - h = wire->name.hash_acc(h); h.acc(offset); + // hash_acc isn't allowed to come first, or it might hash trivially + // and possibly ruin things + h = wire->name.hash_acc(h); return h; } h.acc(data); From 52b0fc03b77b09968653a7943cc095e39f087132 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 4 Nov 2024 12:41:00 +0100 Subject: [PATCH 12/26] hash: solo hashing interface, override for SigBit --- kernel/hashlib.h | 58 ++++++++++++++++++++++++++++++++++-------------- kernel/rtlil.h | 28 ++++++++++++++++++++--- 2 files changed, 66 insertions(+), 20 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index aa9f43ff4d3..3b33748d3c9 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -56,11 +56,25 @@ const int hashtable_size_factor = 3; #define DJB2_32 +namespace legacy { + inline uint32_t mkhash_add(uint32_t a, uint32_t b) { + return ((a << 5) + a) + b; + } +}; - +/** + * Hash a type with an accumulator in a record or array context + */ template struct hash_ops; +/** + * Hash a single instance in isolation. + * Can have explicit specialization, but the default redirects to hash_ops + */ +template +struct hash_top_ops; + inline unsigned int mkhash_xorshift(unsigned int a) { if (sizeof(a) == 4) { a ^= a << 13; @@ -141,6 +155,16 @@ class Hasher { } }; +template +struct hash_top_ops { + static inline bool cmp(const T &a, const T &b) { + return hash_ops::cmp(a, b); + } + static inline Hasher hash(const T &a) { + return hash_ops::hash_acc(a, Hasher()); + } +}; + template struct hash_ops { static inline bool cmp(const T &a, const T &b) { @@ -339,12 +363,12 @@ inline int hashtable_size(int min_size) throw std::length_error("hash table exceeded maximum size."); } -template class dict; -template class idict; -template class pool; -template class mfp; +template> class dict; +template> class idict; +template> class pool; +template> class mfp; -template +template class dict { struct entry_t { @@ -359,7 +383,7 @@ class dict { std::vector hashtable; std::vector entries; - hash_ops ops; + OPS ops; #ifdef NDEBUG static inline void do_assert(bool) { } @@ -373,7 +397,7 @@ class dict { { Hasher::hash_t hash = 0; if (!hashtable.empty()) - hash = run_hash(key) % (unsigned int)(hashtable.size()); + hash = ops.hash(key).yield() % (unsigned int)(hashtable.size()); return hash; } @@ -800,10 +824,10 @@ class dict { const_iterator end() const { return const_iterator(nullptr, -1); } }; -template +template class pool { - template friend class idict; + template friend class idict; protected: struct entry_t @@ -818,7 +842,7 @@ class pool std::vector hashtable; std::vector entries; - hash_ops ops; + OPS ops; #ifdef NDEBUG static inline void do_assert(bool) { } @@ -832,7 +856,7 @@ class pool { Hasher::hash_t hash = 0; if (!hashtable.empty()) - hash = run_hash(key) % (unsigned int)(hashtable.size()); + hash = ops.hash(key).yield() % (unsigned int)(hashtable.size()); return hash; } @@ -1148,7 +1172,7 @@ class pool Hasher hash_acc(Hasher h) const { h.acc(entries.size()); for (auto &it : entries) { - h.commutative_acc(run_hash(it.udata)); + h.commutative_acc(ops.hash(it.udata).yield()); } return h; } @@ -1167,10 +1191,10 @@ class pool const_iterator end() const { return const_iterator(nullptr, -1); } }; -template +template class idict { - pool database; + pool database; public: class const_iterator @@ -1264,10 +1288,10 @@ class idict * mfp stands for "merge, find, promote" * i-prefixed methods operate on indices in parents */ -template +template class mfp { - mutable idict database; + mutable idict database; mutable std::vector parents; public: diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 4f95504781c..afa538540c9 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -896,6 +896,19 @@ struct RTLIL::SigBit bool operator ==(const RTLIL::SigBit &other) const; bool operator !=(const RTLIL::SigBit &other) const; Hasher hash_acc(Hasher h) const; + Hasher hash_top() const; +}; + +namespace hashlib { + template <> + struct hash_top_ops { + static inline bool cmp(const RTLIL::SigBit &a, const RTLIL::SigBit &b) { + return a == b; + } + static inline Hasher hash(const RTLIL::SigBit sb) { + return sb.hash_top(); + } + }; }; struct RTLIL::SigSpecIterator @@ -1825,15 +1838,24 @@ inline bool RTLIL::SigBit::operator!=(const RTLIL::SigBit &other) const { inline Hasher RTLIL::SigBit::hash_acc(Hasher h) const { if (wire) { h.acc(offset); - // hash_acc isn't allowed to come first, or it might hash trivially - // and possibly ruin things - h = wire->name.hash_acc(h); + h.acc(wire->name); return h; } h.acc(data); return h; } + +inline Hasher RTLIL::SigBit::hash_top() const { + Hasher h; + if (wire) { + h.force(hashlib::legacy::mkhash_add(wire->name.index_, offset)); + return h; + } + h.force(data); + return h; +} + inline RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const { return (*sig_p)[index]; } From 704a58ab21ec8591540b0a1d59f2c86054994dd3 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 4 Nov 2024 13:11:33 +0100 Subject: [PATCH 13/26] hashlib: restore hash_obj_ops for pointers to indexed types --- kernel/yosys_common.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/kernel/yosys_common.h b/kernel/yosys_common.h index 9370de33078..954a2a53fbf 100644 --- a/kernel/yosys_common.h +++ b/kernel/yosys_common.h @@ -215,6 +215,26 @@ using RTLIL::State; using RTLIL::SigChunk; using RTLIL::SigSig; +namespace hashlib { + 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 {}; + 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 {}; +} + void memhasher_on(); void memhasher_off(); void memhasher_do(); From 02a578365a781411895d26eaacc043b7d19d85cd Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 6 Nov 2024 12:58:04 +0100 Subject: [PATCH 14/26] hashlib: remove is_new from HasherDJB32, implement hash_top for IdString --- kernel/hashlib.h | 26 +-- kernel/rtlil.h | 533 ++++++++++++++++++++++++----------------------- 2 files changed, 280 insertions(+), 279 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 3b33748d3c9..f1d87163213 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -48,14 +48,9 @@ namespace hashlib { * 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; -#define DJB2_32 - namespace legacy { inline uint32_t mkhash_add(uint32_t a, uint32_t b) { return ((a << 5) + a) + b; @@ -89,16 +84,11 @@ inline unsigned int mkhash_xorshift(unsigned int a) { return a; } -class Hasher { - public: - #ifdef DJB2_32 +class HasherDJB32 { +public: using hash_t = uint32_t; - #endif - #ifdef DJB2_64 - using hash_t = uint64_t; - #endif - Hasher() { + HasherDJB32() { // traditionally 5381 is used as starting value for the djb2 hash state = 5381; } @@ -106,7 +96,7 @@ class Hasher { fudge = f; } - private: +private: uint32_t state; static uint32_t fudge; // The XOR version of DJB2 @@ -142,19 +132,17 @@ class Hasher { *this = hash_ops::hash_acc(t, *this); } - void commutative_acc(uint32_t t) { + void commutative_acc(hash_t t) { state ^= t; } void force(hash_t new_state) { state = new_state; } - - bool is_new() const { - return state == Hasher().state; - } }; +using Hasher = HasherDJB32; + template struct hash_top_ops { static inline bool cmp(const T &a, const T &b) { diff --git a/kernel/rtlil.h b/kernel/rtlil.h index afa538540c9..b17b82c4737 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -76,335 +76,348 @@ namespace RTLIL struct SyncRule; struct Process; struct Binding; + struct IdString; typedef std::pair SigSig; +}; - struct IdString - { - #undef YOSYS_XTRACE_GET_PUT - #undef YOSYS_SORT_ID_FREE_LIST - #undef YOSYS_USE_STICKY_IDS - #undef YOSYS_NO_IDS_REFCNT - - // the global id string cache +struct RTLIL::IdString +{ + #undef YOSYS_XTRACE_GET_PUT + #undef YOSYS_SORT_ID_FREE_LIST + #undef YOSYS_USE_STICKY_IDS + #undef YOSYS_NO_IDS_REFCNT + + // the global id string cache + + static bool destruct_guard_ok; // POD, will be initialized to zero + static struct destruct_guard_t { + destruct_guard_t() { destruct_guard_ok = true; } + ~destruct_guard_t() { destruct_guard_ok = false; } + } destruct_guard; + + static std::vector global_id_storage_; + static dict global_id_index_; +#ifndef YOSYS_NO_IDS_REFCNT + static std::vector global_refcount_storage_; + static std::vector global_free_idx_list_; +#endif - static bool destruct_guard_ok; // POD, will be initialized to zero - static struct destruct_guard_t { - destruct_guard_t() { destruct_guard_ok = true; } - ~destruct_guard_t() { destruct_guard_ok = false; } - } destruct_guard; +#ifdef YOSYS_USE_STICKY_IDS + static int last_created_idx_ptr_; + static int last_created_idx_[8]; +#endif - static std::vector global_id_storage_; - static dict global_id_index_; - #ifndef YOSYS_NO_IDS_REFCNT - static std::vector global_refcount_storage_; - static std::vector global_free_idx_list_; + static inline void xtrace_db_dump() + { + #ifdef YOSYS_XTRACE_GET_PUT + for (int idx = 0; idx < GetSize(global_id_storage_); idx++) + { + if (global_id_storage_.at(idx) == nullptr) + log("#X# DB-DUMP index %d: FREE\n", idx); + else + log("#X# DB-DUMP index %d: '%s' (ref %d)\n", idx, global_id_storage_.at(idx), global_refcount_storage_.at(idx)); + } #endif + } + static inline void checkpoint() + { #ifdef YOSYS_USE_STICKY_IDS - static int last_created_idx_ptr_; - static int last_created_idx_[8]; + last_created_idx_ptr_ = 0; + for (int i = 0; i < 8; i++) { + if (last_created_idx_[i]) + put_reference(last_created_idx_[i]); + last_created_idx_[i] = 0; + } #endif + #ifdef YOSYS_SORT_ID_FREE_LIST + std::sort(global_free_idx_list_.begin(), global_free_idx_list_.end(), std::greater()); + #endif + } - static inline void xtrace_db_dump() - { - #ifdef YOSYS_XTRACE_GET_PUT - for (int idx = 0; idx < GetSize(global_id_storage_); idx++) - { - if (global_id_storage_.at(idx) == nullptr) - log("#X# DB-DUMP index %d: FREE\n", idx); - else - log("#X# DB-DUMP index %d: '%s' (ref %d)\n", idx, global_id_storage_.at(idx), global_refcount_storage_.at(idx)); - } - #endif + static inline int get_reference(int idx) + { + if (idx) { + #ifndef YOSYS_NO_IDS_REFCNT + global_refcount_storage_[idx]++; + #endif + #ifdef YOSYS_XTRACE_GET_PUT + if (yosys_xtrace) + log("#X# GET-BY-INDEX '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx)); + #endif } + return idx; + } - static inline void checkpoint() - { - #ifdef YOSYS_USE_STICKY_IDS - last_created_idx_ptr_ = 0; - for (int i = 0; i < 8; i++) { - if (last_created_idx_[i]) - put_reference(last_created_idx_[i]); - last_created_idx_[i] = 0; - } - #endif - #ifdef YOSYS_SORT_ID_FREE_LIST - std::sort(global_free_idx_list_.begin(), global_free_idx_list_.end(), std::greater()); - #endif - } + static int get_reference(const char *p) + { + log_assert(destruct_guard_ok); - static inline int get_reference(int idx) - { - if (idx) { - #ifndef YOSYS_NO_IDS_REFCNT - global_refcount_storage_[idx]++; - #endif - #ifdef YOSYS_XTRACE_GET_PUT - if (yosys_xtrace) - log("#X# GET-BY-INDEX '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx)); - #endif - } - return idx; - } + if (!p[0]) + return 0; - static int get_reference(const char *p) - { - log_assert(destruct_guard_ok); - - if (!p[0]) - return 0; - - auto it = global_id_index_.find((char*)p); - if (it != global_id_index_.end()) { - #ifndef YOSYS_NO_IDS_REFCNT - global_refcount_storage_.at(it->second)++; - #endif - #ifdef YOSYS_XTRACE_GET_PUT - if (yosys_xtrace) - log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(it->second), it->second, global_refcount_storage_.at(it->second)); - #endif - return it->second; - } + auto it = global_id_index_.find((char*)p); + if (it != global_id_index_.end()) { + #ifndef YOSYS_NO_IDS_REFCNT + global_refcount_storage_.at(it->second)++; + #endif + #ifdef YOSYS_XTRACE_GET_PUT + if (yosys_xtrace) + log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(it->second), it->second, global_refcount_storage_.at(it->second)); + #endif + return it->second; + } - log_assert(p[0] == '$' || p[0] == '\\'); - log_assert(p[1] != 0); - for (const char *c = p; *c; c++) - if ((unsigned)*c <= (unsigned)' ') - log_error("Found control character or space (0x%02x) in string '%s' which is not allowed in RTLIL identifiers\n", *c, p); - - #ifndef YOSYS_NO_IDS_REFCNT - if (global_free_idx_list_.empty()) { - if (global_id_storage_.empty()) { - global_refcount_storage_.push_back(0); - global_id_storage_.push_back((char*)""); - global_id_index_[global_id_storage_.back()] = 0; - } - log_assert(global_id_storage_.size() < 0x40000000); - global_free_idx_list_.push_back(global_id_storage_.size()); - global_id_storage_.push_back(nullptr); - global_refcount_storage_.push_back(0); - } + log_assert(p[0] == '$' || p[0] == '\\'); + log_assert(p[1] != 0); + for (const char *c = p; *c; c++) + if ((unsigned)*c <= (unsigned)' ') + log_error("Found control character or space (0x%02x) in string '%s' which is not allowed in RTLIL identifiers\n", *c, p); - int idx = global_free_idx_list_.back(); - global_free_idx_list_.pop_back(); - global_id_storage_.at(idx) = strdup(p); - global_id_index_[global_id_storage_.at(idx)] = idx; - global_refcount_storage_.at(idx)++; - #else + #ifndef YOSYS_NO_IDS_REFCNT + if (global_free_idx_list_.empty()) { if (global_id_storage_.empty()) { + global_refcount_storage_.push_back(0); global_id_storage_.push_back((char*)""); global_id_index_[global_id_storage_.back()] = 0; } - int idx = global_id_storage_.size(); - global_id_storage_.push_back(strdup(p)); - global_id_index_[global_id_storage_.back()] = idx; - #endif - - if (yosys_xtrace) { - log("#X# New IdString '%s' with index %d.\n", p, idx); - log_backtrace("-X- ", yosys_xtrace-1); - } + log_assert(global_id_storage_.size() < 0x40000000); + global_free_idx_list_.push_back(global_id_storage_.size()); + global_id_storage_.push_back(nullptr); + global_refcount_storage_.push_back(0); + } - #ifdef YOSYS_XTRACE_GET_PUT - if (yosys_xtrace) - log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx)); - #endif - - #ifdef YOSYS_USE_STICKY_IDS - // Avoid Create->Delete->Create pattern - if (last_created_idx_[last_created_idx_ptr_]) - put_reference(last_created_idx_[last_created_idx_ptr_]); - last_created_idx_[last_created_idx_ptr_] = idx; - get_reference(last_created_idx_[last_created_idx_ptr_]); - last_created_idx_ptr_ = (last_created_idx_ptr_ + 1) & 7; - #endif - - return idx; + int idx = global_free_idx_list_.back(); + global_free_idx_list_.pop_back(); + global_id_storage_.at(idx) = strdup(p); + global_id_index_[global_id_storage_.at(idx)] = idx; + global_refcount_storage_.at(idx)++; + #else + if (global_id_storage_.empty()) { + global_id_storage_.push_back((char*)""); + global_id_index_[global_id_storage_.back()] = 0; } + int idx = global_id_storage_.size(); + global_id_storage_.push_back(strdup(p)); + global_id_index_[global_id_storage_.back()] = idx; + #endif - #ifndef YOSYS_NO_IDS_REFCNT - static inline void put_reference(int idx) - { - // put_reference() may be called from destructors after the destructor of - // global_refcount_storage_ has been run. in this case we simply do nothing. - if (!destruct_guard_ok || !idx) - return; - - #ifdef YOSYS_XTRACE_GET_PUT - if (yosys_xtrace) { - log("#X# PUT '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx)); - } - #endif + if (yosys_xtrace) { + log("#X# New IdString '%s' with index %d.\n", p, idx); + log_backtrace("-X- ", yosys_xtrace-1); + } - int &refcount = global_refcount_storage_[idx]; + #ifdef YOSYS_XTRACE_GET_PUT + if (yosys_xtrace) + log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx)); + #endif - if (--refcount > 0) - return; + #ifdef YOSYS_USE_STICKY_IDS + // Avoid Create->Delete->Create pattern + if (last_created_idx_[last_created_idx_ptr_]) + put_reference(last_created_idx_[last_created_idx_ptr_]); + last_created_idx_[last_created_idx_ptr_] = idx; + get_reference(last_created_idx_[last_created_idx_ptr_]); + last_created_idx_ptr_ = (last_created_idx_ptr_ + 1) & 7; + #endif - log_assert(refcount == 0); - free_reference(idx); - } - static inline void free_reference(int idx) - { - if (yosys_xtrace) { - log("#X# Removed IdString '%s' with index %d.\n", global_id_storage_.at(idx), idx); - log_backtrace("-X- ", yosys_xtrace-1); - } + return idx; + } - global_id_index_.erase(global_id_storage_.at(idx)); - free(global_id_storage_.at(idx)); - global_id_storage_.at(idx) = nullptr; - global_free_idx_list_.push_back(idx); +#ifndef YOSYS_NO_IDS_REFCNT + static inline void put_reference(int idx) + { + // put_reference() may be called from destructors after the destructor of + // global_refcount_storage_ has been run. in this case we simply do nothing. + if (!destruct_guard_ok || !idx) + return; + + #ifdef YOSYS_XTRACE_GET_PUT + if (yosys_xtrace) { + log("#X# PUT '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx)); } - #else - static inline void put_reference(int) { } #endif - // the actual IdString object is just is a single int - - int index_; + int &refcount = global_refcount_storage_[idx]; - inline IdString() : index_(0) { } - inline IdString(const char *str) : index_(get_reference(str)) { } - inline IdString(const IdString &str) : index_(get_reference(str.index_)) { } - inline IdString(IdString &&str) : index_(str.index_) { str.index_ = 0; } - inline IdString(const std::string &str) : index_(get_reference(str.c_str())) { } - inline ~IdString() { put_reference(index_); } + if (--refcount > 0) + return; - inline void operator=(const IdString &rhs) { - put_reference(index_); - index_ = get_reference(rhs.index_); + log_assert(refcount == 0); + free_reference(idx); + } + static inline void free_reference(int idx) + { + if (yosys_xtrace) { + log("#X# Removed IdString '%s' with index %d.\n", global_id_storage_.at(idx), idx); + log_backtrace("-X- ", yosys_xtrace-1); } - inline void operator=(const char *rhs) { - IdString id(rhs); - *this = id; - } + global_id_index_.erase(global_id_storage_.at(idx)); + free(global_id_storage_.at(idx)); + global_id_storage_.at(idx) = nullptr; + global_free_idx_list_.push_back(idx); + } +#else + static inline void put_reference(int) { } +#endif - inline void operator=(const std::string &rhs) { - IdString id(rhs); - *this = id; - } + // the actual IdString object is just is a single int - inline const char *c_str() const { - return global_id_storage_.at(index_); - } + int index_; - inline std::string str() const { - return std::string(global_id_storage_.at(index_)); - } + inline IdString() : index_(0) { } + inline IdString(const char *str) : index_(get_reference(str)) { } + inline IdString(const IdString &str) : index_(get_reference(str.index_)) { } + inline IdString(IdString &&str) : index_(str.index_) { str.index_ = 0; } + inline IdString(const std::string &str) : index_(get_reference(str.c_str())) { } + inline ~IdString() { put_reference(index_); } - inline bool operator<(const IdString &rhs) const { - return index_ < rhs.index_; - } + inline void operator=(const IdString &rhs) { + put_reference(index_); + index_ = get_reference(rhs.index_); + } - inline bool operator==(const IdString &rhs) const { return index_ == rhs.index_; } - inline bool operator!=(const IdString &rhs) const { return index_ != rhs.index_; } + inline void operator=(const char *rhs) { + IdString id(rhs); + *this = id; + } - // The methods below are just convenience functions for better compatibility with std::string. + inline void operator=(const std::string &rhs) { + IdString id(rhs); + *this = id; + } - bool operator==(const std::string &rhs) const { return c_str() == rhs; } - bool operator!=(const std::string &rhs) const { return c_str() != rhs; } + inline const char *c_str() const { + return global_id_storage_.at(index_); + } - bool operator==(const char *rhs) const { return strcmp(c_str(), rhs) == 0; } - bool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; } + inline std::string str() const { + return std::string(global_id_storage_.at(index_)); + } - char operator[](size_t i) const { - const char *p = c_str(); + inline bool operator<(const IdString &rhs) const { + return index_ < rhs.index_; + } + + inline bool operator==(const IdString &rhs) const { return index_ == rhs.index_; } + inline bool operator!=(const IdString &rhs) const { return index_ != rhs.index_; } + + // The methods below are just convenience functions for better compatibility with std::string. + + bool operator==(const std::string &rhs) const { return c_str() == rhs; } + bool operator!=(const std::string &rhs) const { return c_str() != rhs; } + + bool operator==(const char *rhs) const { return strcmp(c_str(), rhs) == 0; } + bool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; } + + char operator[](size_t i) const { + const char *p = c_str(); #ifndef NDEBUG - for (; i != 0; i--, p++) - log_assert(*p != 0); - return *p; + for (; i != 0; i--, p++) + log_assert(*p != 0); + return *p; #else - return *(p + i); + return *(p + i); #endif - } + } - std::string substr(size_t pos = 0, size_t len = std::string::npos) const { - if (len == std::string::npos || len >= strlen(c_str() + pos)) - return std::string(c_str() + pos); - else - return std::string(c_str() + pos, len); - } + std::string substr(size_t pos = 0, size_t len = std::string::npos) const { + if (len == std::string::npos || len >= strlen(c_str() + pos)) + return std::string(c_str() + pos); + else + return std::string(c_str() + pos, len); + } - int compare(size_t pos, size_t len, const char* s) const { - return strncmp(c_str()+pos, s, len); - } + int compare(size_t pos, size_t len, const char* s) const { + return strncmp(c_str()+pos, s, len); + } - bool begins_with(const char* prefix) const { - size_t len = strlen(prefix); - if (size() < len) return false; - return compare(0, len, prefix) == 0; - } + bool begins_with(const char* prefix) const { + size_t len = strlen(prefix); + if (size() < len) return false; + return compare(0, len, prefix) == 0; + } - bool ends_with(const char* suffix) const { - size_t len = strlen(suffix); - if (size() < len) return false; - return compare(size()-len, len, suffix) == 0; - } + bool ends_with(const char* suffix) const { + size_t len = strlen(suffix); + if (size() < len) return false; + return compare(size()-len, len, suffix) == 0; + } - bool contains(const char* str) const { - return strstr(c_str(), str); - } + bool contains(const char* str) const { + return strstr(c_str(), str); + } - size_t size() const { - return strlen(c_str()); - } + size_t size() const { + return strlen(c_str()); + } - bool empty() const { - return c_str()[0] == 0; - } + bool empty() const { + return c_str()[0] == 0; + } - void clear() { - *this = IdString(); - } + void clear() { + *this = IdString(); + } - Hasher hash_acc(Hasher h) const { - // If we're starting a hashing sequence, simply start with unhashed ID - if (h.is_new()) { - h.force((Hasher::hash_t) index_); - return h; - } + Hasher hash_acc(Hasher h) const { return hash_ops::hash_acc(index_, h); } - return hash_ops::hash_acc(index_, h); - } + Hasher hash_top() const { + Hasher h; + h.force((Hasher::hash_t) index_); + return h; + } - // The following is a helper key_compare class. Instead of for example std::set - // use std::set> if the order of cells in the - // set has an influence on the algorithm. + // The following is a helper key_compare class. Instead of for example std::set + // use std::set> if the order of cells in the + // set has an influence on the algorithm. - template struct compare_ptr_by_name { - bool operator()(const T *a, const T *b) const { - return (a == nullptr || b == nullptr) ? (a < b) : (a->name < b->name); - } - }; + template struct compare_ptr_by_name { + bool operator()(const T *a, const T *b) const { + return (a == nullptr || b == nullptr) ? (a < b) : (a->name < b->name); + } + }; - // often one needs to check if a given IdString is part of a list (for example a list - // of cell types). the following functions helps with that. + // often one needs to check if a given IdString is part of a list (for example a list + // of cell types). the following functions helps with that. + template + bool in(Args... args) const { + return (... || in(args)); + } - template - bool in(Args... args) const { - // Credit: https://articles.emptycrate.com/2016/05/14/folds_in_cpp11_ish.html - bool result = false; - (void) std::initializer_list{ (result = result || in(args), 0)... }; - return result; - } + bool in(const IdString &rhs) const { return *this == rhs; } + bool in(const char *rhs) const { return *this == rhs; } + bool in(const std::string &rhs) const { return *this == rhs; } + inline bool in(const pool &rhs) const; + inline bool in(const pool &&rhs) const; - bool in(const IdString &rhs) const { return *this == rhs; } - bool in(const char *rhs) const { return *this == rhs; } - bool in(const std::string &rhs) const { return *this == rhs; } - bool in(const pool &rhs) const { return rhs.count(*this) != 0; } + bool isPublic() const { return begins_with("\\"); } +}; - bool isPublic() const { return begins_with("\\"); } +namespace hashlib { + template <> + struct hash_top_ops { + static inline bool cmp(const RTLIL::IdString &a, const RTLIL::IdString &b) { + return a == b; + } + static inline Hasher hash(const RTLIL::IdString id) { + return id.hash_top(); + } }; +}; + +// TODO deprecate this +inline bool RTLIL::IdString::in(const pool &rhs) const { return rhs.count(*this) != 0; } +inline bool RTLIL::IdString::in(const pool &&rhs) const { return rhs.count(*this) != 0; } +namespace RTLIL { namespace ID { #define X(_id) extern IdString _id; #include "kernel/constids.inc" #undef X }; - extern dict constpad; const pool &builtin_ff_cell_types(); From 0dafe06cd48a6ec20a2bd26db49cf6ddceb00d1f Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 6 Nov 2024 17:44:15 +0100 Subject: [PATCH 15/26] hashlib: run_hash uses hash_top_ops, not hash_ops --- kernel/hashlib.h | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index f1d87163213..b185eeed496 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -278,18 +278,9 @@ struct hash_obj_ops { template [[nodiscard]] Hasher::hash_t run_hash(const T& obj) { - Hasher h; - h.acc(obj); - return h.yield(); + return hash_top_ops::hash(obj).yield(); } -// #ifdef OTHER_HASH... - -// [[deprecated]] -// inline unsigned int mkhash_add(unsigned int a, unsigned int b) { -// return mkhash(a, b); -// } - template<> struct hash_ops { static inline bool cmp(std::monostate a, std::monostate b) { return a == b; From ad0dc177114869c9604b3855eb8c8a15dff31690 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 6 Nov 2024 18:05:29 +0100 Subject: [PATCH 16/26] docs: document the ideas behind the hashing interface --- docs/source/yosys_internals/hashing.rst | 45 +++++++++++++++++++++++++ kernel/hashlib.h | 2 ++ 2 files changed, 47 insertions(+) create mode 100644 docs/source/yosys_internals/hashing.rst diff --git a/docs/source/yosys_internals/hashing.rst b/docs/source/yosys_internals/hashing.rst new file mode 100644 index 00000000000..ba4e08af203 --- /dev/null +++ b/docs/source/yosys_internals/hashing.rst @@ -0,0 +1,45 @@ +Hashing and associative data structures in Yosys +------------------------------------------------ + +Yosys heavily relies on custom data structures such as dict or pool +defined in kernel/hashlib.h. There are various reasons for this. + +The hash function +~~~~~~~~~~~~~~~~~ + +The hash function generally used in Yosys is the XOR version of DJB2: + +``state = ((state << 5) + state) ^ value`` + +This is an old-school hash designed to hash ASCII characters. Yosys doesn't hash a lot of ASCII text, but it still happens to be a local optimum due to factors described later. + +Hash function quality is multi-faceted and highly dependent on what is being hashed. Yosys isn't concerned by any cryptographic qualities, instead the goal is minimizing total hashing collision risk given the data patterns within Yosys. +In general, a good hash function typically folds values into a state accumulator with a mathematical function that is fast to compute and has some beneficial properties. One of these is the avalanche property, which demands that a small change such as flipping a bit or incrementing by one in the input produces a large, unpredictable change in the output. Additionally, the bit independence criterion states that any pair of output bits should change independently when any single input bit is inverted. These properties are important for avoiding hash collision on data patterns like the hash of a sequence not colliding with its permutation, not losing from the state the information added by hashing preceding elements, etc. + +DJB2 lacks these properties. Instead, since Yosys hashes large numbers of data structures composed of incrementing integer IDs, Yosys abuses the predictability of DJB2 to get lower hash collisions, with regular nature of the hashes surviving through the interaction with the "modulo prime" operations in the associative data structures. For example, some most common objects in Yosys are interned ``IdString``s of incrementing indices or ``SigBit``s with bit offsets into wire (represented by its unique ``IdString`` name) as the typical case. This is what makes DJB2 a local optimum. Additionally, the ADD version of DJB2 (like above but with addition instead of XOR) is used to this end for some types, abandoning the general pattern of folding values into a state value. + +Making a type hashable +~~~~~~~~~~~~~~~~~~~~~~ + +Let's first take a look at the external interface on a simplified level. Generally, to get the hash for ``T obj``, you would call the utility function ``run_hash(const T& obj)``, corresponding to ``hash_top_ops::hash(obj)``, the default implementation of which is ``hash_ops::hash_acc(Hasher(), obj)``. ``Hasher`` is the class actually implementing the hash function, hiding its initialized internal state, and passing it out on ``hash_t yield()`` with perhaps some finalization steps. + +``hash_ops`` is the star of the show. By default it pulls the ``Hasher h`` through a ``Hasher T::hash_acc(Hasher h)`` method. That's the method you have to implement to make a record (class or struct) type easily hashable with Yosys hashlib associative data structures. + +``hash_ops`` is specialized for built-in types like ``int`` or ``bool`` and treats pointers the same as integers, so it doesn't dereference pointers. Since many RTLIL data structures like ``RTLIL::Wire`` carry their own unique index ``Hasher::hash_t hashidx_;``, there are specializations for ``hash_ops`` and others in ``kernel/hashlib.h`` that actually dereference the pointers and call ``hash_acc`` on the instances pointed to. + +``hash_ops`` is also specialized for simple compound types like ``std::pair`` by calling hash_acc in sequence on its members. For flexible size containers like ``std::vector`` the size of the container is hashed first. That is also how implementing hashing for a custom record data type should be - unless there is strong reason to do otherwise, call ``h.acc(m)`` on the ``Hasher h`` you have received for each member in sequence and ``return h;``. If you do have a strong reason to do so, look at how ``hash_top_ops`` is implemented in ``kernel/rtlil.h``. + +Porting plugins from the legacy interface +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, the interface to implement hashing on custom types was just ``unsigned int T::hash() const``. This meant hashes for members were computed independently and then ad-hoc combined with the hash function with some xorshift operations thrown in to mix bits together somewhat. A plugin can stay compatible with both versions prior and after the break by implementing the aforementioned current interface and redirecting the legacy one: + +``void Hasher::acc(const T& t)`` hashes ``t`` into its internal state by also redirecting to ``hash_ops`` + +.. code-block:: cpp + :caption: Example hash compatibility wrapper + :name: hash_plugin_compat + inline unsigned int T::hash() const { + Hasher h; + return (unsigned int)hash_acc(h).yield(); + } diff --git a/kernel/hashlib.h b/kernel/hashlib.h index b185eeed496..ca2a04cece4 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -25,6 +25,8 @@ namespace hashlib { /** * HASHING * + * Also refer to docs/source/yosys_internals/hashing.rst + * * 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. * From 04547874439d3aa986e16d72f7e48c8088566941 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Thu, 7 Nov 2024 10:35:02 +1300 Subject: [PATCH 17/26] Docs: Formatting and fixes --- docs/source/yosys_internals/hashing.rst | 96 +++++++++++++++++++------ docs/source/yosys_internals/index.rst | 1 + 2 files changed, 74 insertions(+), 23 deletions(-) diff --git a/docs/source/yosys_internals/hashing.rst b/docs/source/yosys_internals/hashing.rst index ba4e08af203..32c4453c804 100644 --- a/docs/source/yosys_internals/hashing.rst +++ b/docs/source/yosys_internals/hashing.rst @@ -1,8 +1,8 @@ Hashing and associative data structures in Yosys ------------------------------------------------ -Yosys heavily relies on custom data structures such as dict or pool -defined in kernel/hashlib.h. There are various reasons for this. +Yosys heavily relies on custom data structures such as dict or pool defined in +kernel/hashlib.h. There are various reasons for this. The hash function ~~~~~~~~~~~~~~~~~ @@ -11,35 +11,85 @@ The hash function generally used in Yosys is the XOR version of DJB2: ``state = ((state << 5) + state) ^ value`` -This is an old-school hash designed to hash ASCII characters. Yosys doesn't hash a lot of ASCII text, but it still happens to be a local optimum due to factors described later. - -Hash function quality is multi-faceted and highly dependent on what is being hashed. Yosys isn't concerned by any cryptographic qualities, instead the goal is minimizing total hashing collision risk given the data patterns within Yosys. -In general, a good hash function typically folds values into a state accumulator with a mathematical function that is fast to compute and has some beneficial properties. One of these is the avalanche property, which demands that a small change such as flipping a bit or incrementing by one in the input produces a large, unpredictable change in the output. Additionally, the bit independence criterion states that any pair of output bits should change independently when any single input bit is inverted. These properties are important for avoiding hash collision on data patterns like the hash of a sequence not colliding with its permutation, not losing from the state the information added by hashing preceding elements, etc. - -DJB2 lacks these properties. Instead, since Yosys hashes large numbers of data structures composed of incrementing integer IDs, Yosys abuses the predictability of DJB2 to get lower hash collisions, with regular nature of the hashes surviving through the interaction with the "modulo prime" operations in the associative data structures. For example, some most common objects in Yosys are interned ``IdString``s of incrementing indices or ``SigBit``s with bit offsets into wire (represented by its unique ``IdString`` name) as the typical case. This is what makes DJB2 a local optimum. Additionally, the ADD version of DJB2 (like above but with addition instead of XOR) is used to this end for some types, abandoning the general pattern of folding values into a state value. +This is an old-school hash designed to hash ASCII characters. Yosys doesn't hash +a lot of ASCII text, but it still happens to be a local optimum due to factors +described later. + +Hash function quality is multi-faceted and highly dependent on what is being +hashed. Yosys isn't concerned by any cryptographic qualities, instead the goal +is minimizing total hashing collision risk given the data patterns within Yosys. +In general, a good hash function typically folds values into a state accumulator +with a mathematical function that is fast to compute and has some beneficial +properties. One of these is the avalanche property, which demands that a small +change such as flipping a bit or incrementing by one in the input produces a +large, unpredictable change in the output. Additionally, the bit independence +criterion states that any pair of output bits should change independently when +any single input bit is inverted. These properties are important for avoiding +hash collision on data patterns like the hash of a sequence not colliding with +its permutation, not losing from the state the information added by hashing +preceding elements, etc. + +DJB2 lacks these properties. Instead, since Yosys hashes large numbers of data +structures composed of incrementing integer IDs, Yosys abuses the predictability +of DJB2 to get lower hash collisions, with regular nature of the hashes +surviving through the interaction with the "modulo prime" operations in the +associative data structures. For example, some most common objects in Yosys are +interned ``IdString``\ s of incrementing indices or ``SigBit``\ s with bit +offsets into wire (represented by its unique ``IdString`` name) as the typical +case. This is what makes DJB2 a local optimum. Additionally, the ADD version of +DJB2 (like above but with addition instead of XOR) is used to this end for some +types, abandoning the general pattern of folding values into a state value. Making a type hashable ~~~~~~~~~~~~~~~~~~~~~~ -Let's first take a look at the external interface on a simplified level. Generally, to get the hash for ``T obj``, you would call the utility function ``run_hash(const T& obj)``, corresponding to ``hash_top_ops::hash(obj)``, the default implementation of which is ``hash_ops::hash_acc(Hasher(), obj)``. ``Hasher`` is the class actually implementing the hash function, hiding its initialized internal state, and passing it out on ``hash_t yield()`` with perhaps some finalization steps. - -``hash_ops`` is the star of the show. By default it pulls the ``Hasher h`` through a ``Hasher T::hash_acc(Hasher h)`` method. That's the method you have to implement to make a record (class or struct) type easily hashable with Yosys hashlib associative data structures. - -``hash_ops`` is specialized for built-in types like ``int`` or ``bool`` and treats pointers the same as integers, so it doesn't dereference pointers. Since many RTLIL data structures like ``RTLIL::Wire`` carry their own unique index ``Hasher::hash_t hashidx_;``, there are specializations for ``hash_ops`` and others in ``kernel/hashlib.h`` that actually dereference the pointers and call ``hash_acc`` on the instances pointed to. - -``hash_ops`` is also specialized for simple compound types like ``std::pair`` by calling hash_acc in sequence on its members. For flexible size containers like ``std::vector`` the size of the container is hashed first. That is also how implementing hashing for a custom record data type should be - unless there is strong reason to do otherwise, call ``h.acc(m)`` on the ``Hasher h`` you have received for each member in sequence and ``return h;``. If you do have a strong reason to do so, look at how ``hash_top_ops`` is implemented in ``kernel/rtlil.h``. +Let's first take a look at the external interface on a simplified level. +Generally, to get the hash for ``T obj``, you would call the utility function +``run_hash(const T& obj)``, corresponding to ``hash_top_ops::hash(obj)``, +the default implementation of which is ``hash_ops::hash_acc(Hasher(), obj)``. +``Hasher`` is the class actually implementing the hash function, hiding its +initialized internal state, and passing it out on ``hash_t yield()`` with +perhaps some finalization steps. + +``hash_ops`` is the star of the show. By default it pulls the ``Hasher h`` +through a ``Hasher T::hash_acc(Hasher h)`` method. That's the method you have to +implement to make a record (class or struct) type easily hashable with Yosys +hashlib associative data structures. + +``hash_ops`` is specialized for built-in types like ``int`` or ``bool`` and +treats pointers the same as integers, so it doesn't dereference pointers. Since +many RTLIL data structures like ``RTLIL::Wire`` carry their own unique index +``Hasher::hash_t hashidx_;``, there are specializations for ``hash_ops`` +and others in ``kernel/hashlib.h`` that actually dereference the pointers and +call ``hash_acc`` on the instances pointed to. + +``hash_ops`` is also specialized for simple compound types like +``std::pair`` by calling hash_acc in sequence on its members. For flexible +size containers like ``std::vector`` the size of the container is hashed +first. That is also how implementing hashing for a custom record data type +should be - unless there is strong reason to do otherwise, call ``h.acc(m)`` on +the ``Hasher h`` you have received for each member in sequence and ``return +h;``. If you do have a strong reason to do so, look at how +``hash_top_ops`` is implemented in ``kernel/rtlil.h``. Porting plugins from the legacy interface ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Previously, the interface to implement hashing on custom types was just ``unsigned int T::hash() const``. This meant hashes for members were computed independently and then ad-hoc combined with the hash function with some xorshift operations thrown in to mix bits together somewhat. A plugin can stay compatible with both versions prior and after the break by implementing the aforementioned current interface and redirecting the legacy one: +Previously, the interface to implement hashing on custom types was just +``unsigned int T::hash() const``. This meant hashes for members were computed +independently and then ad-hoc combined with the hash function with some xorshift +operations thrown in to mix bits together somewhat. A plugin can stay compatible +with both versions prior and after the break by implementing the aforementioned +current interface and redirecting the legacy one: -``void Hasher::acc(const T& t)`` hashes ``t`` into its internal state by also redirecting to ``hash_ops`` +``void Hasher::acc(const T& t)`` hashes ``t`` into its internal state by also +redirecting to ``hash_ops`` .. code-block:: cpp - :caption: Example hash compatibility wrapper - :name: hash_plugin_compat - inline unsigned int T::hash() const { - Hasher h; - return (unsigned int)hash_acc(h).yield(); - } + :caption: Example hash compatibility wrapper + :name: hash_plugin_compat + + inline unsigned int T::hash() const { + Hasher h; + return (unsigned int)hash_acc(h).yield(); + } diff --git a/docs/source/yosys_internals/index.rst b/docs/source/yosys_internals/index.rst index 9631e865331..3dd4224faf1 100644 --- a/docs/source/yosys_internals/index.rst +++ b/docs/source/yosys_internals/index.rst @@ -39,3 +39,4 @@ as reference to implement a similar system in any language. extending_yosys/index techmap verilog + hashing From 1401906d8122b09e40c174167432ce36bddc63e7 Mon Sep 17 00:00:00 2001 From: Emil J Date: Thu, 7 Nov 2024 00:26:01 +0100 Subject: [PATCH 18/26] docs: formatting and fixes Co-authored-by: KrystalDelusion <93062060+KrystalDelusion@users.noreply.github.com> --- docs/source/yosys_internals/hashing.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/source/yosys_internals/hashing.rst b/docs/source/yosys_internals/hashing.rst index 32c4453c804..372be05ecfd 100644 --- a/docs/source/yosys_internals/hashing.rst +++ b/docs/source/yosys_internals/hashing.rst @@ -9,7 +9,9 @@ The hash function The hash function generally used in Yosys is the XOR version of DJB2: -``state = ((state << 5) + state) ^ value`` +:: + + state = ((state << 5) + state) ^ value This is an old-school hash designed to hash ASCII characters. Yosys doesn't hash a lot of ASCII text, but it still happens to be a local optimum due to factors From 6d53454bf5061e38834d9604c86546d9e03df4b4 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 11 Nov 2024 13:14:49 +0100 Subject: [PATCH 19/26] docs: move hashing-based container details into internal docs from guidelines --- docs/source/yosys_internals/hashing.rst | 54 +++++++++++++++++++++++- guidelines/GettingStarted | 56 ++++--------------------- 2 files changed, 59 insertions(+), 51 deletions(-) diff --git a/docs/source/yosys_internals/hashing.rst b/docs/source/yosys_internals/hashing.rst index 372be05ecfd..b88bf122327 100644 --- a/docs/source/yosys_internals/hashing.rst +++ b/docs/source/yosys_internals/hashing.rst @@ -1,8 +1,58 @@ Hashing and associative data structures in Yosys ------------------------------------------------ -Yosys heavily relies on custom data structures such as dict or pool defined in -kernel/hashlib.h. There are various reasons for this. +Container classes based on hashing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Yosys uses ``dict`` and ``pool`` as main container classes. +``dict`` is essentially a replacement for ``std::unordered_map`` +and ``pool`` is a replacement for ``std::unordered_set``. +The main characteristics are: + +* ``dict`` and ``pool`` are about 2x faster than the std containers + (though this claim hasn't been verified for over 10 years) + +* references to elements in a ``dict`` or ``pool`` are invalidated by + insert and remove operations (similar to ``std::vector`` on ``push_back()``). + +* some iterators are invalidated by ``erase()``. specifically, iterators + that have not passed the erased element yet are invalidated. (``erase()`` + itself returns valid iterator to the next element.) + +* no iterators are invalidated by ``insert()``. elements are inserted at + ``begin()``. i.e. only a new iterator that starts at ``begin()`` will see the + inserted elements. + +* the method ``.count(key, iterator)`` is like ``.count(key)`` but only + considers elements that can be reached via the iterator. + +* iterators can be compared. ``it1 < it2`` means that the position of ``t2`` + can be reached via ``t1`` but not vice versa. + +* the method ``.sort()`` can be used to sort the elements in the container + the container stays sorted until elements are added or removed. + +* ``dict`` and ``pool`` will have the same order of iteration across + all compilers, standard libraries and architectures. + +In addition to ``dict`` and ``pool`` there is also an ``idict`` that +creates a bijective map from ``K`` to the integers. For example: + +:: + + idict si; + log("%d\n", si("hello")); // will print 42 + log("%d\n", si("world")); // will print 43 + log("%d\n", si.at("world")); // will print 43 + log("%d\n", si.at("dummy")); // will throw exception + log("%s\n", si[42].c_str())); // will print hello + log("%s\n", si[43].c_str())); // will print world + log("%s\n", si[44].c_str())); // will throw exception + +It is not possible to remove elements from an idict. + +Finally ``mfp`` implements a merge-find set data structure (aka. disjoint-set +or union-find) over the type ``K`` ("mfp" = merge-find-promote). The hash function ~~~~~~~~~~~~~~~~~ diff --git a/guidelines/GettingStarted b/guidelines/GettingStarted index 110f6318518..17fe325233d 100644 --- a/guidelines/GettingStarted +++ b/guidelines/GettingStarted @@ -37,57 +37,15 @@ And then executed using the following command: Yosys Data Structures --------------------- -Here is a short list of data structures that you should make yourself familiar -with before you write C++ code for Yosys. The following data structures are all -defined when "kernel/yosys.h" is included and USING_YOSYS_NAMESPACE is used. + 1. Container classes based on hashing - 1. Yosys Container Classes +Yosys heavily relies on custom container data structures such as dict or pool +defined in kernel/hashlib.h. +dict is essentially a replacement for std::unordered_map +and pool is a replacement for std::unordered_set. Please refer to +docs/source/yosys_internals/hashing.rst for more information on those. -Yosys uses dict and pool as main container classes. dict is -essentially a replacement for std::unordered_map and pool is a -replacement for std::unordered_set. The main characteristics are: - - - dict and pool are about 2x faster than the std containers - - - references to elements in a dict or pool are invalidated by - insert and remove operations (similar to std::vector on push_back()). - - - some iterators are invalidated by erase(). specifically, iterators - that have not passed the erased element yet are invalidated. (erase() - itself returns valid iterator to the next element.) - - - no iterators are invalidated by insert(). elements are inserted at - begin(). i.e. only a new iterator that starts at begin() will see the - inserted elements. - - - the method .count(key, iterator) is like .count(key) but only - considers elements that can be reached via the iterator. - - - iterators can be compared. it1 < it2 means that the position of t2 - can be reached via t1 but not vice versa. - - - the method .sort() can be used to sort the elements in the container - the container stays sorted until elements are added or removed. - - - dict and pool will have the same order of iteration across - all compilers, standard libraries and architectures. - -In addition to dict and pool there is also an idict that -creates a bijective map from K to the integers. For example: - - idict si; - log("%d\n", si("hello")); // will print 42 - log("%d\n", si("world")); // will print 43 - log("%d\n", si.at("world")); // will print 43 - log("%d\n", si.at("dummy")); // will throw exception - log("%s\n", si[42].c_str())); // will print hello - log("%s\n", si[43].c_str())); // will print world - log("%s\n", si[44].c_str())); // will throw exception - -It is not possible to remove elements from an idict. - -Finally mfp implements a merge-find set data structure (aka. disjoint-set or -union-find) over the type K ("mfp" = merge-find-promote). +Otherwise, Yosys makes use of the following: 2. Standard STL data types From 79acc141d58966c2422b04d81dce00297d888ab2 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 11 Nov 2024 13:27:04 +0100 Subject: [PATCH 20/26] hashlib: add deprecated mkhash function to prevent plugin breakage --- docs/source/yosys_internals/hashing.rst | 6 ++++++ kernel/hashlib.h | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/docs/source/yosys_internals/hashing.rst b/docs/source/yosys_internals/hashing.rst index b88bf122327..0d74f9014df 100644 --- a/docs/source/yosys_internals/hashing.rst +++ b/docs/source/yosys_internals/hashing.rst @@ -145,3 +145,9 @@ redirecting to ``hash_ops`` Hasher h; return (unsigned int)hash_acc(h).yield(); } + +To get hashes for Yosys types, you can temporarily use the templated deprecated +``mkhash`` function until the majority of your plugin's users switch to a newer +version and live with the warnings, or set up a custom ``#ifdef``-based solution +if you really need to. +Feel free to contact Yosys maintainers with related issues. diff --git a/kernel/hashlib.h b/kernel/hashlib.h index ca2a04cece4..df6a4853c72 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -103,19 +103,19 @@ class HasherDJB32 { static uint32_t fudge; // The XOR version of DJB2 [[nodiscard]] - static uint32_t mkhash(uint32_t a, uint32_t b) { + static uint32_t djb2_xor(uint32_t a, uint32_t b) { uint32_t hash = ((a << 5) + a) ^ b; return hash; } public: void hash32(uint32_t i) { - state = mkhash(i, state); + state = djb2_xor(i, state); state = mkhash_xorshift(fudge ^ state); return; } void hash64(uint64_t i) { - state = mkhash((uint32_t)(i % (1ULL << 32ULL)), state); - state = mkhash((uint32_t)(i >> 32ULL), state); + state = djb2_xor((uint32_t)(i % (1ULL << 32ULL)), state); + state = djb2_xor((uint32_t)(i >> 32ULL), state); state = mkhash_xorshift(fudge ^ state); return; } @@ -283,6 +283,14 @@ Hasher::hash_t run_hash(const T& obj) { return hash_top_ops::hash(obj).yield(); } +/** Refer to docs/source/yosys_internals/hashing.rst */ +template +[[nodiscard]] +[[deprecated]] +inline unsigned int mkhash(const T &v) { + return (unsigned int) run_hash(v); +} + template<> struct hash_ops { static inline bool cmp(std::monostate a, std::monostate b) { return a == b; From 4e29ec18543d290e599f921be3120b7470aad020 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 11 Nov 2024 15:45:11 +0100 Subject: [PATCH 21/26] hashlib: acc -> eat --- docs/source/yosys_internals/hashing.rst | 14 +-- flake.nix | 8 +- frontends/ast/ast.h | 2 +- kernel/bitpattern.h | 4 +- kernel/cellaigs.cc | 16 ++-- kernel/cellaigs.h | 4 +- kernel/drivertools.h | 120 ++++++++++++------------ kernel/functional.h | 8 +- kernel/hashlib.h | 84 ++++++++--------- kernel/modtools.h | 16 ++-- kernel/rtlil.cc | 8 +- kernel/rtlil.h | 32 +++---- kernel/scopeinfo.h | 6 +- kernel/sigtools.h | 12 +-- kernel/timinginfo.h | 12 +-- kernel/yosys_common.h | 4 +- kernel/yw.h | 2 +- passes/cmds/dft_tag.cc | 2 +- passes/cmds/example_dt.cc | 6 +- passes/equiv/equiv_struct.cc | 10 +- passes/proc/proc_dlatch.cc | 8 +- passes/sat/recover_names.cc | 12 +-- passes/techmap/clockgate.cc | 4 +- passes/techmap/flowmap.cc | 4 +- techlibs/quicklogic/ql_dsp_simd.cc | 2 +- 25 files changed, 200 insertions(+), 200 deletions(-) diff --git a/docs/source/yosys_internals/hashing.rst b/docs/source/yosys_internals/hashing.rst index 0d74f9014df..b6d8df6efc4 100644 --- a/docs/source/yosys_internals/hashing.rst +++ b/docs/source/yosys_internals/hashing.rst @@ -98,13 +98,13 @@ Making a type hashable Let's first take a look at the external interface on a simplified level. Generally, to get the hash for ``T obj``, you would call the utility function ``run_hash(const T& obj)``, corresponding to ``hash_top_ops::hash(obj)``, -the default implementation of which is ``hash_ops::hash_acc(Hasher(), obj)``. +the default implementation of which is ``hash_ops::hash_eat(Hasher(), obj)``. ``Hasher`` is the class actually implementing the hash function, hiding its initialized internal state, and passing it out on ``hash_t yield()`` with perhaps some finalization steps. ``hash_ops`` is the star of the show. By default it pulls the ``Hasher h`` -through a ``Hasher T::hash_acc(Hasher h)`` method. That's the method you have to +through a ``Hasher T::hash_eat(Hasher h)`` method. That's the method you have to implement to make a record (class or struct) type easily hashable with Yosys hashlib associative data structures. @@ -113,13 +113,13 @@ treats pointers the same as integers, so it doesn't dereference pointers. Since many RTLIL data structures like ``RTLIL::Wire`` carry their own unique index ``Hasher::hash_t hashidx_;``, there are specializations for ``hash_ops`` and others in ``kernel/hashlib.h`` that actually dereference the pointers and -call ``hash_acc`` on the instances pointed to. +call ``hash_eat`` on the instances pointed to. ``hash_ops`` is also specialized for simple compound types like -``std::pair`` by calling hash_acc in sequence on its members. For flexible +``std::pair`` by calling hash_eat in sequence on its members. For flexible size containers like ``std::vector`` the size of the container is hashed first. That is also how implementing hashing for a custom record data type -should be - unless there is strong reason to do otherwise, call ``h.acc(m)`` on +should be - unless there is strong reason to do otherwise, call ``h.eat(m)`` on the ``Hasher h`` you have received for each member in sequence and ``return h;``. If you do have a strong reason to do so, look at how ``hash_top_ops`` is implemented in ``kernel/rtlil.h``. @@ -134,7 +134,7 @@ operations thrown in to mix bits together somewhat. A plugin can stay compatible with both versions prior and after the break by implementing the aforementioned current interface and redirecting the legacy one: -``void Hasher::acc(const T& t)`` hashes ``t`` into its internal state by also +``void Hasher::eat(const T& t)`` hashes ``t`` into its internal state by also redirecting to ``hash_ops`` .. code-block:: cpp @@ -143,7 +143,7 @@ redirecting to ``hash_ops`` inline unsigned int T::hash() const { Hasher h; - return (unsigned int)hash_acc(h).yield(); + return (unsigned int)hash_eat(h).yield(); } To get hashes for Yosys types, you can temporarily use the templated deprecated diff --git a/flake.nix b/flake.nix index 90fa5328c09..19ba59f17c4 100644 --- a/flake.nix +++ b/flake.nix @@ -14,15 +14,15 @@ }; # TODO: don't override src when ./abc is empty # which happens when the command used is `nix build` and not `nix build ?submodules=1` - abc-verifier = pkgs.abc-verifier.overrideAttrs(x: y: {src = ./abc;}); + abc-verifier = pkgs.abc-verifier; yosys = pkgs.clangStdenv.mkDerivation { name = "yosys"; src = ./. ; - buildInputs = with pkgs; [ clang bison flex libffi tcl readline python3 llvmPackages.libcxxClang zlib git pkg-configUpstream llvmPackages.bintools ]; + buildInputs = with pkgs; [ clang bison flex libffi tcl readline python3 zlib git pkg-configUpstream llvmPackages.bintools ]; checkInputs = with pkgs; [ gtest ]; propagatedBuildInputs = [ abc-verifier ]; preConfigure = "make config-clang"; - checkTarget = "test"; + checkTarget = "unit-test"; installPhase = '' make install PREFIX=$out ABCEXTERNAL=yosys-abc ln -s ${abc-verifier}/bin/abc $out/bin/yosys-abc @@ -41,7 +41,7 @@ packages.default = yosys; defaultPackage = yosys; devShell = pkgs.mkShell { - buildInputs = with pkgs; [ clang llvmPackages.bintools bison flex libffi tcl readline python3 llvmPackages.libcxxClang zlib git gtest abc-verifier ]; + buildInputs = with pkgs; [ clang llvmPackages.bintools gcc bison flex libffi tcl readline python3 zlib git gtest abc-verifier verilog boost python3Packages.boost ]; }; } ); diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 1a72e62850e..47221903481 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -177,7 +177,7 @@ namespace AST { // for dict<> and pool<> unsigned int hashidx_; - Hasher hash_acc(Hasher h) const { h.acc(hashidx_); return h; } + Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } // this nodes type AstNodeType type; diff --git a/kernel/bitpattern.h b/kernel/bitpattern.h index 3814f4672b2..7752acc4297 100644 --- a/kernel/bitpattern.h +++ b/kernel/bitpattern.h @@ -43,10 +43,10 @@ struct BitPatternPool return false; return bitdata == other.bitdata; } - Hasher hash_acc(Hasher h) const { + Hasher hash_eat(Hasher h) const { if (!cached_hash) cached_hash = run_hash(bitdata); - h.acc(cached_hash); + h.eat(cached_hash); return h; } }; diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc index 81b486c79f8..63bbbca3704 100644 --- a/kernel/cellaigs.cc +++ b/kernel/cellaigs.cc @@ -39,13 +39,13 @@ bool AigNode::operator==(const AigNode &other) const return true; } -Hasher AigNode::hash_acc(Hasher h) const +Hasher AigNode::hash_eat(Hasher h) const { - h.acc(portname); - h.acc(portbit); - h.acc(inverter); - h.acc(left_parent); - h.acc(right_parent); + h.eat(portname); + h.eat(portbit); + h.eat(inverter); + h.eat(left_parent); + h.eat(right_parent); return h; } @@ -54,9 +54,9 @@ bool Aig::operator==(const Aig &other) const return name == other.name; } -Hasher Aig::hash_acc(Hasher h) const +Hasher Aig::hash_eat(Hasher h) const { - h.acc(name); + h.eat(name); return h; } diff --git a/kernel/cellaigs.h b/kernel/cellaigs.h index bdb8b3c073c..8d3f0312002 100644 --- a/kernel/cellaigs.h +++ b/kernel/cellaigs.h @@ -34,7 +34,7 @@ struct AigNode AigNode(); bool operator==(const AigNode &other) const; - Hasher hash_acc(Hasher h) const; + Hasher hash_eat(Hasher h) const; }; struct Aig @@ -44,7 +44,7 @@ struct Aig Aig(Cell *cell); bool operator==(const Aig &other) const; - Hasher hash_acc(Hasher h) const; + Hasher hash_eat(Hasher h) const; }; YOSYS_NAMESPACE_END diff --git a/kernel/drivertools.h b/kernel/drivertools.h index 0e7b872e4ba..b46c1e2b60a 100644 --- a/kernel/drivertools.h +++ b/kernel/drivertools.h @@ -74,7 +74,7 @@ struct DriveBitWire return offset < other.offset; } - Hasher hash_acc(Hasher h) const; + Hasher hash_eat(Hasher h) const; operator SigBit() const @@ -105,7 +105,7 @@ struct DriveBitPort return offset < other.offset; } - Hasher hash_acc(Hasher h) const; + Hasher hash_eat(Hasher h) const; }; @@ -129,7 +129,7 @@ struct DriveBitMarker return offset < other.offset; } - Hasher hash_acc(Hasher h) const; + Hasher hash_eat(Hasher h) const; }; @@ -164,7 +164,7 @@ struct DriveBitMultiple return multiple_ == other.multiple_; } - Hasher hash_acc(Hasher h) const; + Hasher hash_eat(Hasher h) const; }; struct DriveBit @@ -352,7 +352,7 @@ struct DriveBit return *this; } - Hasher hash_acc(Hasher h) const; + Hasher hash_eat(Hasher h) const; bool operator==(const DriveBit &other) const { @@ -473,7 +473,7 @@ struct DriveChunkWire return offset < other.offset; } - Hasher hash_acc(Hasher h) const; + Hasher hash_eat(Hasher h) const; explicit operator SigChunk() const { @@ -531,7 +531,7 @@ struct DriveChunkPort return offset < other.offset; } - Hasher hash_acc(Hasher h) const; + Hasher hash_eat(Hasher h) const; }; @@ -572,7 +572,7 @@ struct DriveChunkMarker return offset < other.offset; } - Hasher hash_acc(Hasher h) const; + Hasher hash_eat(Hasher h) const; }; struct DriveChunkMultiple @@ -612,7 +612,7 @@ struct DriveChunkMultiple return false; // TODO implement, canonicalize order } - Hasher hash_acc(Hasher h) const; + Hasher hash_eat(Hasher h) const; }; struct DriveChunk @@ -863,7 +863,7 @@ struct DriveChunk bool try_append(DriveBit const &bit); bool try_append(DriveChunk const &chunk); - Hasher hash_acc(Hasher h) const; + Hasher hash_eat(Hasher h) const; bool operator==(const DriveChunk &other) const { @@ -1073,7 +1073,7 @@ struct DriveSpec that->hash_ |= (that->hash_ == 0); } - Hasher hash_acc(Hasher h) const; + Hasher hash_eat(Hasher h) const; bool operator==(DriveSpec const &other) const { updhash(); @@ -1112,7 +1112,7 @@ struct DriverMap 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; } - Hasher hash_acc(Hasher h) const; + Hasher hash_eat(Hasher h) const; }; // Essentially a dict> but using less memory // and fewer allocations @@ -1258,130 +1258,130 @@ struct DriverMap } }; -inline Hasher DriveBitWire::hash_acc(Hasher h) const +inline Hasher DriveBitWire::hash_eat(Hasher h) const { - h.acc(wire->name); - h.acc(offset); + h.eat(wire->name); + h.eat(offset); return h; } -inline Hasher DriveBitPort::hash_acc(Hasher h) const +inline Hasher DriveBitPort::hash_eat(Hasher h) const { - h.acc(cell->name); - h.acc(port); - h.acc(offset); + h.eat(cell->name); + h.eat(port); + h.eat(offset); return h; } -inline Hasher DriveBitMarker::hash_acc(Hasher h) const +inline Hasher DriveBitMarker::hash_eat(Hasher h) const { - h.acc(marker); - h.acc(offset); + h.eat(marker); + h.eat(offset); return h; } -inline Hasher DriveBitMultiple::hash_acc(Hasher h) const +inline Hasher DriveBitMultiple::hash_eat(Hasher h) const { - h.acc(multiple_); + h.eat(multiple_); return h; } -inline Hasher DriveBit::hash_acc(Hasher h) const +inline Hasher DriveBit::hash_eat(Hasher h) const { switch (type_) { case DriveType::NONE: - h.acc(0); + h.eat(0); break; case DriveType::CONSTANT: - h.acc(constant_); + h.eat(constant_); break; case DriveType::WIRE: - h.acc(wire_); + h.eat(wire_); break; case DriveType::PORT: - h.acc(port_); + h.eat(port_); break; case DriveType::MARKER: - h.acc(marker_); + h.eat(marker_); break; case DriveType::MULTIPLE: - h.acc(multiple_); + h.eat(multiple_); break; } - h.acc(type_); + h.eat(type_); return h; } -inline Hasher DriveChunkWire::hash_acc(Hasher h) const +inline Hasher DriveChunkWire::hash_eat(Hasher h) const { - h.acc(wire->name); - h.acc(width); - h.acc(offset); + h.eat(wire->name); + h.eat(width); + h.eat(offset); return h; } -inline Hasher DriveChunkPort::hash_acc(Hasher h) const +inline Hasher DriveChunkPort::hash_eat(Hasher h) const { - h.acc(cell->name); - h.acc(port); - h.acc(width); - h.acc(offset); + h.eat(cell->name); + h.eat(port); + h.eat(width); + h.eat(offset); return h; } -inline Hasher DriveChunkMarker::hash_acc(Hasher h) const +inline Hasher DriveChunkMarker::hash_eat(Hasher h) const { - h.acc(marker); - h.acc(width); - h.acc(offset); + h.eat(marker); + h.eat(width); + h.eat(offset); return h; } -inline Hasher DriveChunkMultiple::hash_acc(Hasher h) const +inline Hasher DriveChunkMultiple::hash_eat(Hasher h) const { - h.acc(width_); - h.acc(multiple_); + h.eat(width_); + h.eat(multiple_); return h; } -inline Hasher DriveChunk::hash_acc(Hasher h) const +inline Hasher DriveChunk::hash_eat(Hasher h) const { switch (type_) { case DriveType::NONE: - h.acc(0); + h.eat(0); break; case DriveType::CONSTANT: - h.acc(constant_); + h.eat(constant_); break; case DriveType::WIRE: - h.acc(wire_); + h.eat(wire_); break; case DriveType::PORT: - h.acc(port_); + h.eat(port_); break; case DriveType::MARKER: - h.acc(marker_); + h.eat(marker_); break; case DriveType::MULTIPLE: - h.acc(multiple_); + h.eat(multiple_); break; } - h.acc(type_); + h.eat(type_); return h; } -inline Hasher DriveSpec::hash_acc(Hasher h) const +inline Hasher DriveSpec::hash_eat(Hasher h) const { if (hash_ == 0) updhash(); - h.acc(hash_); + h.eat(hash_); return h; } -inline Hasher DriverMap::DriveBitId::hash_acc(Hasher h) const +inline Hasher DriverMap::DriveBitId::hash_eat(Hasher h) const { - h.acc(id); + h.eat(id); return h; } diff --git a/kernel/functional.h b/kernel/functional.h index b80c77be45b..790190e08ae 100644 --- a/kernel/functional.h +++ b/kernel/functional.h @@ -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; } - Hasher hash_acc(Hasher h) const { h.acc(_v); return h; } + Hasher hash_eat(Hasher h) const { h.eat(_v); return h; } }; class IR; class Factory; @@ -225,9 +225,9 @@ namespace Functional { const RTLIL::Const &as_const() const { return std::get(_extra); } std::pair as_idstring_pair() const { return std::get>(_extra); } int as_int() const { return std::get(_extra); } - Hasher hash_acc(Hasher h) const { - h.acc((unsigned int) _fn); - h.acc(_extra); + Hasher hash_eat(Hasher h) const { + h.eat((unsigned int) _fn); + h.eat(_extra); return h; } bool operator==(NodeData const &other) const { diff --git a/kernel/hashlib.h b/kernel/hashlib.h index df6a4853c72..f66baa4297d 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -125,16 +125,16 @@ class HasherDJB32 { } template - void acc(T&& t) { - *this = hash_ops>>::hash_acc(std::forward(t), *this); + void eat(T&& t) { + *this = hash_ops>>::hash_eat(std::forward(t), *this); } template - void acc(const T& t) { - *this = hash_ops::hash_acc(t, *this); + void eat(const T& t) { + *this = hash_ops::hash_eat(t, *this); } - void commutative_acc(hash_t t) { + void commutative_eat(hash_t t) { state ^= t; } @@ -151,7 +151,7 @@ struct hash_top_ops { return hash_ops::cmp(a, b); } static inline Hasher hash(const T &a) { - return hash_ops::hash_acc(a, Hasher()); + return hash_ops::hash_eat(a, Hasher()); } }; @@ -160,7 +160,7 @@ struct hash_ops { static inline bool cmp(const T &a, const T &b) { return a == b; } - static inline Hasher hash_acc(const T &a, Hasher h) { + static inline Hasher hash_eat(const T &a, Hasher h) { if constexpr (std::is_same_v) { h.hash32(a ? 1 : 0); return h; @@ -173,15 +173,15 @@ struct hash_ops { return h; } else if constexpr (std::is_enum_v) { using u_type = std::underlying_type_t; - return hash_ops::hash_acc((u_type) a, h); + return hash_ops::hash_eat((u_type) a, h); } else if constexpr (std::is_pointer_v) { - return hash_ops::hash_acc((uintptr_t) a, h); + return hash_ops::hash_eat((uintptr_t) a, h); } else if constexpr (std::is_same_v) { for (auto c : a) h.hash32(c); return h; } else { - return a.hash_acc(h); + return a.hash_eat(h); } } }; @@ -190,9 +190,9 @@ template struct hash_ops> { static inline bool cmp(std::pair a, std::pair b) { return a == b; } - static inline Hasher hash_acc(std::pair a, Hasher h) { - h = hash_ops

::hash_acc(a.first, h); - h = hash_ops::hash_acc(a.second, h); + static inline Hasher hash_eat(std::pair a, Hasher h) { + h = hash_ops

::hash_eat(a.first, h); + h = hash_ops::hash_eat(a.second, h); return h; } }; @@ -202,14 +202,14 @@ template struct hash_ops> { return a == b; } template - static inline typename std::enable_if::type hash_acc(std::tuple, Hasher h) { + static inline typename std::enable_if::type hash_eat(std::tuple, Hasher h) { return h; } template - static inline typename std::enable_if::type hash_acc(std::tuple a, Hasher h) { + static inline typename std::enable_if::type hash_eat(std::tuple a, Hasher h) { typedef hash_ops>::type> element_ops_t; - h = hash_acc(a, h); - h = element_ops_t::hash_acc(std::get(a), h); + h = hash_eat(a, h); + h = element_ops_t::hash_eat(std::get(a), h); return h; } }; @@ -218,10 +218,10 @@ template struct hash_ops> { static inline bool cmp(std::vector a, std::vector b) { return a == b; } - static inline Hasher hash_acc(std::vector a, Hasher h) { - h.acc(a.size()); + static inline Hasher hash_eat(std::vector a, Hasher h) { + h.eat(a.size()); for (auto k : a) - h.acc(k); + h.eat(k); return h; } }; @@ -230,9 +230,9 @@ template struct hash_ops> { static inline bool cmp(std::array a, std::array b) { return a == b; } - static inline Hasher hash_acc(std::array a, Hasher h) { + static inline Hasher hash_eat(std::array a, Hasher h) { for (const auto& k : a) - h = hash_ops::hash_acc(k, h); + h = hash_ops::hash_eat(k, h); return h; } }; @@ -244,7 +244,7 @@ struct hash_cstr_ops { return false; return true; } - static inline Hasher hash_acc(const char *a, Hasher h) { + static inline Hasher hash_eat(const char *a, Hasher h) { while (*a) h.hash32(*(a++)); return h; @@ -257,8 +257,8 @@ struct hash_ptr_ops { static inline bool cmp(const void *a, const void *b) { return a == b; } - static inline Hasher hash_acc(const void *a, Hasher h) { - return hash_ops::hash_acc((uintptr_t)a, h); + static inline Hasher hash_eat(const void *a, Hasher h) { + return hash_ops::hash_eat((uintptr_t)a, h); } }; @@ -267,8 +267,8 @@ struct hash_obj_ops { return a == b; } template - static inline Hasher hash_acc(const T *a, Hasher h) { - return a ? a->hash_acc(h) : h; + static inline Hasher hash_eat(const T *a, Hasher h) { + return a ? a->hash_eat(h) : h; } }; /** @@ -295,7 +295,7 @@ template<> struct hash_ops { static inline bool cmp(std::monostate a, std::monostate b) { return a == b; } - static inline Hasher hash_acc(std::monostate, Hasher h) { + static inline Hasher hash_eat(std::monostate, Hasher h) { return h; } }; @@ -304,9 +304,9 @@ template struct hash_ops> { static inline bool cmp(std::variant a, std::variant b) { return a == b; } - static inline Hasher hash_acc(std::variant a, Hasher h) { - std::visit([& h](const auto &v) { h.acc(v); }, a); - h.acc(a.index()); + static inline Hasher hash_eat(std::variant a, Hasher h) { + std::visit([& h](const auto &v) { h.eat(v); }, a); + h.eat(a.index()); return h; } }; @@ -315,11 +315,11 @@ template struct hash_ops> { static inline bool cmp(std::optional a, std::optional b) { return a == b; } - static inline Hasher hash_acc(std::optional a, Hasher h) { + static inline Hasher hash_eat(std::optional a, Hasher h) { if(a.has_value()) - h.acc(*a); + h.eat(*a); else - h.acc(0); + h.eat(0); return h; } }; @@ -788,13 +788,13 @@ class dict { return !operator==(other); } - Hasher hash_acc(Hasher h) const { - h.acc(entries.size()); + Hasher hash_eat(Hasher h) const { + h.eat(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()); + entry_hash.eat(it.udata.first); + entry_hash.eat(it.udata.second); + h.commutative_eat(entry_hash.yield()); } return h; } @@ -1158,10 +1158,10 @@ class pool return !operator==(other); } - Hasher hash_acc(Hasher h) const { - h.acc(entries.size()); + Hasher hash_eat(Hasher h) const { + h.eat(entries.size()); for (auto &it : entries) { - h.commutative_acc(ops.hash(it.udata).yield()); + h.commutative_eat(ops.hash(it.udata).yield()); } return h; } diff --git a/kernel/modtools.h b/kernel/modtools.h index 1afa0ad502a..fce22d8579d 100644 --- a/kernel/modtools.h +++ b/kernel/modtools.h @@ -48,10 +48,10 @@ struct ModIndex : public RTLIL::Monitor return cell == other.cell && port == other.port && offset == other.offset; } - Hasher hash_acc(Hasher h) const { - h.acc(cell->name); - h.acc(port); - h.acc(offset); + Hasher hash_eat(Hasher h) const { + h.eat(cell->name); + h.eat(port); + h.eat(offset); return h; } }; @@ -324,10 +324,10 @@ struct ModWalker return cell == other.cell && port == other.port && offset == other.offset; } - Hasher hash_acc(Hasher h) const { - h.acc(cell->name); - h.acc(port); - h.acc(offset); + Hasher hash_eat(Hasher h) const { + h.eat(cell->name); + h.eat(port); + h.eat(offset); return h; } }; diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 65510362e6d..cb0f7da7807 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4480,11 +4480,11 @@ void RTLIL::SigSpec::updhash() const for (auto &c : that->chunks_) if (c.wire == NULL) { for (auto &v : c.data) - h.acc(v); + h.eat(v); } else { - h.acc(c.wire->name.index_); - h.acc(c.offset); - h.acc(c.width); + h.eat(c.wire->name.index_); + h.eat(c.offset); + h.eat(c.width); } that->hash_ = h.yield(); if (that->hash_ == 0) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index b17b82c4737..eaf2eaf8ead 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -362,7 +362,7 @@ struct RTLIL::IdString *this = IdString(); } - Hasher hash_acc(Hasher h) const { return hash_ops::hash_acc(index_, h); } + Hasher hash_eat(Hasher h) const { return hash_ops::hash_eat(index_, h); } Hasher hash_top() const { Hasher h; @@ -815,10 +815,10 @@ struct RTLIL::Const bv.resize(width, bv.empty() ? RTLIL::State::Sx : bv.back()); } - inline Hasher hash_acc(Hasher h) const { + inline Hasher hash_eat(Hasher h) const { // TODO hash size for (auto b : *this) - h.acc(b); + h.eat(b); return h; } }; @@ -908,7 +908,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; - Hasher hash_acc(Hasher h) const; + Hasher hash_eat(Hasher h) const; Hasher hash_top() const; }; @@ -1115,7 +1115,7 @@ struct RTLIL::SigSpec operator std::vector() const { return bits(); } const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; } - Hasher hash_acc(Hasher h) const { if (!hash_) updhash(); h.acc(hash_); return h; } + Hasher hash_eat(Hasher h) const { if (!hash_) updhash(); h.eat(hash_); return h; } #ifndef NDEBUG void check(Module *mod = nullptr) const; @@ -1157,7 +1157,7 @@ struct RTLIL::Selection struct RTLIL::Monitor { Hasher::hash_t hashidx_; - Hasher hash_acc(Hasher h) const { h.acc(hashidx_); return h; } + Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } Monitor() { static unsigned int hashidx_count = 123456789; @@ -1180,7 +1180,7 @@ struct define_map_t; struct RTLIL::Design { Hasher::hash_t hashidx_; - Hasher hash_acc(Hasher h) const { h.acc(hashidx_); return h; } + Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } pool monitors; dict scratchpad; @@ -1285,7 +1285,7 @@ struct RTLIL::Design struct RTLIL::Module : public RTLIL::AttrObject { Hasher::hash_t hashidx_; - Hasher hash_acc(Hasher h) const { h.acc(hashidx_); return h; } + Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } protected: void add(RTLIL::Wire *wire); @@ -1640,7 +1640,7 @@ void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire); struct RTLIL::Wire : public RTLIL::AttrObject { Hasher::hash_t hashidx_; - Hasher hash_acc(Hasher h) const { h.acc(hashidx_); return h; } + Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } protected: // use module->addWire() and module->remove() to create or destroy wires @@ -1679,7 +1679,7 @@ inline int GetSize(RTLIL::Wire *wire) { struct RTLIL::Memory : public RTLIL::AttrObject { Hasher::hash_t hashidx_; - Hasher hash_acc(Hasher h) const { h.acc(hashidx_); return h; } + Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } Memory(); @@ -1694,7 +1694,7 @@ struct RTLIL::Memory : public RTLIL::AttrObject struct RTLIL::Cell : public RTLIL::AttrObject { Hasher::hash_t hashidx_; - Hasher hash_acc(Hasher h) const { h.acc(hashidx_); return h; } + Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } protected: // use module->addCell() and module->remove() to create or destroy cells @@ -1804,7 +1804,7 @@ struct RTLIL::SyncRule struct RTLIL::Process : public RTLIL::AttrObject { Hasher::hash_t hashidx_; - Hasher hash_acc(Hasher h) const { h.acc(hashidx_); return h; } + Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } protected: // use module->addProcess() and module->remove() to create or destroy processes @@ -1848,13 +1848,13 @@ inline bool RTLIL::SigBit::operator!=(const RTLIL::SigBit &other) const { return (wire != other.wire) || (wire ? (offset != other.offset) : (data != other.data)); } -inline Hasher RTLIL::SigBit::hash_acc(Hasher h) const { +inline Hasher RTLIL::SigBit::hash_eat(Hasher h) const { if (wire) { - h.acc(offset); - h.acc(wire->name); + h.eat(offset); + h.eat(wire->name); return h; } - h.acc(data); + h.eat(data); return h; } diff --git a/kernel/scopeinfo.h b/kernel/scopeinfo.h index fa550dab638..3c9ca69b690 100644 --- a/kernel/scopeinfo.h +++ b/kernel/scopeinfo.h @@ -171,8 +171,8 @@ class IdTree Hasher hash_acc(Hasher h) const { - h.acc(scope_name); - h.acc(target); + h.eat(scope_name); + h.eat(target); return h; } @@ -325,7 +325,7 @@ struct ModuleItem { Cell *cell() const { return type == Type::Cell ? static_cast(ptr) : nullptr; } bool operator==(const ModuleItem &other) const { return ptr == other.ptr && type == other.type; } - Hasher hash_acc(Hasher h) const { h.acc(ptr); return h; } + Hasher hash_eat(Hasher h) const { h.eat(ptr); return h; } }; static inline void log_dump_val_worker(typename IdTree::Cursor cursor ) { log("%p %s", cursor.target, log_id(cursor.scope_name)); } diff --git a/kernel/sigtools.h b/kernel/sigtools.h index f3779c37c4e..c827807aadb 100644 --- a/kernel/sigtools.h +++ b/kernel/sigtools.h @@ -29,9 +29,9 @@ struct SigPool struct bitDef_t : public std::pair { bitDef_t() : std::pair(NULL, 0) { } bitDef_t(const RTLIL::SigBit &bit) : std::pair(bit.wire, bit.offset) { } - Hasher hash_acc(Hasher h) const { - h.acc(first->name); - h.acc(second); + Hasher hash_eat(Hasher h) const { + h.eat(first->name); + h.eat(second); return h; } }; @@ -147,9 +147,9 @@ struct SigSet struct bitDef_t : public std::pair { bitDef_t() : std::pair(NULL, 0) { } bitDef_t(const RTLIL::SigBit &bit) : std::pair(bit.wire, bit.offset) { } - Hasher hash_acc(Hasher h) const { - h.acc(first->name); - h.acc(second); + Hasher hash_eat(Hasher h) const { + h.eat(first->name); + h.eat(second); return h; } }; diff --git a/kernel/timinginfo.h b/kernel/timinginfo.h index 373615f59fc..e294d29a7e5 100644 --- a/kernel/timinginfo.h +++ b/kernel/timinginfo.h @@ -44,9 +44,9 @@ struct TimingInfo return {}; return port[offset]; } - Hasher hash_acc(Hasher h) const { - h.acc(name); - h.acc(offset); + Hasher hash_eat(Hasher h) const { + h.eat(name); + h.eat(offset); return h; } }; @@ -56,9 +56,9 @@ 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; } - Hasher hash_acc(Hasher h) const { - h.acc(first); - h.acc(second); + Hasher hash_eat(Hasher h) const { + h.eat(first); + h.eat(second); return h; } }; diff --git a/kernel/yosys_common.h b/kernel/yosys_common.h index 954a2a53fbf..b194718f113 100644 --- a/kernel/yosys_common.h +++ b/kernel/yosys_common.h @@ -171,8 +171,8 @@ 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; } - Hasher hash_acc(Hasher h) const { - h.acc(*content); + Hasher hash_eat(Hasher h) const { + h.eat(*content); return h; } }; diff --git a/kernel/yw.h b/kernel/yw.h index a4bae55152b..e16d4986609 100644 --- a/kernel/yw.h +++ b/kernel/yw.h @@ -35,7 +35,7 @@ struct IdPath : public std::vector bool has_address() const { int tmp; return get_address(tmp); }; bool get_address(int &addr) const; - Hasher hash_acc(Hasher h) const { h.acc(*this); return h; } + Hasher hash_eat(Hasher h) const { h.eat(*this); return h; } }; struct WitnessHierarchyItem { diff --git a/passes/cmds/dft_tag.cc b/passes/cmds/dft_tag.cc index 0b1127a11a9..2a5fb690efb 100644 --- a/passes/cmds/dft_tag.cc +++ b/passes/cmds/dft_tag.cc @@ -47,7 +47,7 @@ struct DftTagWorker { bool operator<(const tag_set &other) const { return index < other.index; } bool operator==(const tag_set &other) const { return index == other.index; } - Hasher hash_acc(Hasher h) const { h.acc(index); return h; } + Hasher hash_eat(Hasher h) const { h.eat(index); return h; } bool empty() const { return index == 0; } }; diff --git a/passes/cmds/example_dt.cc b/passes/cmds/example_dt.cc index 97ce26327bb..7cd1d2f24a5 100644 --- a/passes/cmds/example_dt.cc +++ b/passes/cmds/example_dt.cc @@ -52,9 +52,9 @@ struct ExampleDtPass : public Pass return name == other.name && parameters == other.parameters; } - Hasher hash_acc(Hasher h) const { - h.acc(name); - h.acc(parameters); + Hasher hash_eat(Hasher h) const { + h.eat(name); + h.eat(parameters); return h; } }; diff --git a/passes/equiv/equiv_struct.cc b/passes/equiv/equiv_struct.cc index 55b364971f7..774c5a1a607 100644 --- a/passes/equiv/equiv_struct.cc +++ b/passes/equiv/equiv_struct.cc @@ -46,11 +46,11 @@ struct EquivStructWorker parameters == other.parameters && port_sizes == other.port_sizes; } - Hasher hash_acc(Hasher h) const { - h.acc(type); - h.acc(parameters); - h.acc(port_sizes); - h.acc(connections); + Hasher hash_eat(Hasher h) const { + h.eat(type); + h.eat(parameters); + h.eat(port_sizes); + h.eat(connections); return h; } }; diff --git a/passes/proc/proc_dlatch.cc b/passes/proc/proc_dlatch.cc index 5936502c09d..6b579b4e4cc 100644 --- a/passes/proc/proc_dlatch.cc +++ b/passes/proc/proc_dlatch.cc @@ -127,10 +127,10 @@ struct proc_dlatch_db_t return signal == other.signal && match == other.match && children == other.children; } - Hasher hash_acc(Hasher h) const { - h.acc(signal); - h.acc(match); - h.acc(children); + Hasher hash_eat(Hasher h) const { + h.eat(signal); + h.eat(match); + h.eat(children); return h; } }; diff --git a/passes/sat/recover_names.cc b/passes/sat/recover_names.cc index 05ddf8e552e..a84380cbf5c 100644 --- a/passes/sat/recover_names.cc +++ b/passes/sat/recover_names.cc @@ -46,10 +46,10 @@ struct IdBit { bool operator==(const IdBit &other) const { return name == other.name && bit == other.bit; }; bool operator!=(const IdBit &other) const { return name != other.name || bit != other.bit; }; - Hasher hash_acc(Hasher h) const + Hasher hash_eat(Hasher h) const { - h.acc(name); - h.acc(bit); + h.eat(name); + h.eat(bit); return h; } @@ -64,10 +64,10 @@ struct InvBit { bool operator==(const InvBit &other) const { return bit == other.bit && inverted == other.inverted; }; bool operator!=(const InvBit &other) const { return bit != other.bit || inverted != other.inverted; }; - Hasher hash_acc(Hasher h) const + Hasher hash_eat(Hasher h) const { - h.acc(bit); - h.acc(inverted); + h.eat(bit); + h.eat(inverted); return h; } diff --git a/passes/techmap/clockgate.cc b/passes/techmap/clockgate.cc index 79c1be7c134..bfd4c8a9724 100644 --- a/passes/techmap/clockgate.cc +++ b/passes/techmap/clockgate.cc @@ -233,9 +233,9 @@ struct ClockgatePass : public Pass { SigBit ce_bit; bool pol_clk; bool pol_ce; - Hasher hash_acc(Hasher h) const { + Hasher hash_eat(Hasher h) const { auto t = std::make_tuple(clk_bit, ce_bit, pol_clk, pol_ce); - h.acc(t); + h.eat(t); return h; } bool operator==(const ClkNetInfo& other) const { diff --git a/passes/techmap/flowmap.cc b/passes/techmap/flowmap.cc index b07097b9967..bfee38999cc 100644 --- a/passes/techmap/flowmap.cc +++ b/passes/techmap/flowmap.cc @@ -250,10 +250,10 @@ struct FlowGraph { return !(*this == other); } - Hasher hash_acc(Hasher h) const + Hasher hash_eat(Hasher h) const { std::pair p = {node, is_bottom}; - h.acc(p); + h.eat(p); return h; } diff --git a/techlibs/quicklogic/ql_dsp_simd.cc b/techlibs/quicklogic/ql_dsp_simd.cc index bcbb290dfa8..162f0c2d683 100644 --- a/techlibs/quicklogic/ql_dsp_simd.cc +++ b/techlibs/quicklogic/ql_dsp_simd.cc @@ -53,7 +53,7 @@ struct QlDspSimdPass : public Pass { DspConfig(const DspConfig &ref) = default; DspConfig(DspConfig &&ref) = default; - Hasher hash_acc(Hasher h) const { h.acc(connections); return h; } + Hasher hash_eat(Hasher h) const { h.eat(connections); return h; } bool operator==(const DspConfig &ref) const { return connections == ref.connections; } }; From 1df8a3e64ba67acab935716eeddae2c2afbd9cab Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 11 Nov 2024 15:46:25 +0100 Subject: [PATCH 22/26] hashlib: legacy mkhash_add -> djb2_add --- kernel/hashlib.h | 2 +- kernel/rtlil.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index f66baa4297d..3be33ebd9ea 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -54,7 +54,7 @@ const int hashtable_size_trigger = 2; const int hashtable_size_factor = 3; namespace legacy { - inline uint32_t mkhash_add(uint32_t a, uint32_t b) { + inline uint32_t djb2_add(uint32_t a, uint32_t b) { return ((a << 5) + a) + b; } }; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index eaf2eaf8ead..2b3d274a2e9 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1862,7 +1862,7 @@ inline Hasher RTLIL::SigBit::hash_eat(Hasher h) const { inline Hasher RTLIL::SigBit::hash_top() const { Hasher h; if (wire) { - h.force(hashlib::legacy::mkhash_add(wire->name.index_, offset)); + h.force(hashlib::legacy::djb2_add(wire->name.index_, offset)); return h; } h.force(data); From 0a525f38c2ddaa6801c73861533dd35dad1ccd40 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 19 Nov 2024 20:01:41 +0100 Subject: [PATCH 23/26] hashlib: declare YS_HASHING_VERSION = 1 --- docs/source/yosys_internals/hashing.rst | 26 +++++++++++++------------ kernel/hashlib.h | 2 ++ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/docs/source/yosys_internals/hashing.rst b/docs/source/yosys_internals/hashing.rst index b6d8df6efc4..0e3e5fc90cb 100644 --- a/docs/source/yosys_internals/hashing.rst +++ b/docs/source/yosys_internals/hashing.rst @@ -131,23 +131,25 @@ Previously, the interface to implement hashing on custom types was just ``unsigned int T::hash() const``. This meant hashes for members were computed independently and then ad-hoc combined with the hash function with some xorshift operations thrown in to mix bits together somewhat. A plugin can stay compatible -with both versions prior and after the break by implementing the aforementioned -current interface and redirecting the legacy one: - -``void Hasher::eat(const T& t)`` hashes ``t`` into its internal state by also -redirecting to ``hash_ops`` +with both versions prior and after the break by implementing both interfaces +based on the existance and value of `YS_HASHING_VERSION`. .. code-block:: cpp :caption: Example hash compatibility wrapper :name: hash_plugin_compat - inline unsigned int T::hash() const { - Hasher h; - return (unsigned int)hash_eat(h).yield(); + #ifndef YS_HASHING_VERSION + unsigned int T::hash() const { + return mkhash(a, b); + } + #elif YS_HASHING_VERSION == 1 + Hasher T::hash_eat(Hasher h) const { + h.eat(a); + h.eat(b); + return h; } + #else + #error "Unsupported hashing interface" + #endif -To get hashes for Yosys types, you can temporarily use the templated deprecated -``mkhash`` function until the majority of your plugin's users switch to a newer -version and live with the warnings, or set up a custom ``#ifdef``-based solution -if you really need to. Feel free to contact Yosys maintainers with related issues. diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 3be33ebd9ea..f9271bd7f86 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -20,6 +20,8 @@ #include #include +#define YS_HASHING_VERSION 1 + namespace hashlib { /** From b9b9515bb06d29229b90af8af92215d59a4649c1 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 19 Nov 2024 20:04:19 +0100 Subject: [PATCH 24/26] hashlib: hash_eat -> hash_into --- docs/source/yosys_internals/hashing.rst | 10 ++--- frontends/ast/ast.h | 2 +- kernel/bitpattern.h | 2 +- kernel/cellaigs.cc | 4 +- kernel/cellaigs.h | 4 +- kernel/drivertools.h | 48 +++++++++++----------- kernel/functional.h | 4 +- kernel/hashlib.h | 54 ++++++++++++------------- kernel/modtools.h | 4 +- kernel/rtlil.h | 24 +++++------ kernel/scopeinfo.h | 4 +- kernel/sigtools.h | 4 +- kernel/timinginfo.h | 4 +- kernel/yosys_common.h | 2 +- kernel/yw.h | 2 +- passes/cmds/dft_tag.cc | 2 +- passes/cmds/example_dt.cc | 2 +- passes/equiv/equiv_struct.cc | 2 +- passes/proc/proc_dlatch.cc | 2 +- passes/sat/recover_names.cc | 4 +- passes/techmap/clockgate.cc | 2 +- passes/techmap/flowmap.cc | 2 +- techlibs/quicklogic/ql_dsp_simd.cc | 2 +- 23 files changed, 95 insertions(+), 95 deletions(-) diff --git a/docs/source/yosys_internals/hashing.rst b/docs/source/yosys_internals/hashing.rst index 0e3e5fc90cb..338ee5fd681 100644 --- a/docs/source/yosys_internals/hashing.rst +++ b/docs/source/yosys_internals/hashing.rst @@ -98,13 +98,13 @@ Making a type hashable Let's first take a look at the external interface on a simplified level. Generally, to get the hash for ``T obj``, you would call the utility function ``run_hash(const T& obj)``, corresponding to ``hash_top_ops::hash(obj)``, -the default implementation of which is ``hash_ops::hash_eat(Hasher(), obj)``. +the default implementation of which is ``hash_ops::hash_into(Hasher(), obj)``. ``Hasher`` is the class actually implementing the hash function, hiding its initialized internal state, and passing it out on ``hash_t yield()`` with perhaps some finalization steps. ``hash_ops`` is the star of the show. By default it pulls the ``Hasher h`` -through a ``Hasher T::hash_eat(Hasher h)`` method. That's the method you have to +through a ``Hasher T::hash_into(Hasher h)`` method. That's the method you have to implement to make a record (class or struct) type easily hashable with Yosys hashlib associative data structures. @@ -113,10 +113,10 @@ treats pointers the same as integers, so it doesn't dereference pointers. Since many RTLIL data structures like ``RTLIL::Wire`` carry their own unique index ``Hasher::hash_t hashidx_;``, there are specializations for ``hash_ops`` and others in ``kernel/hashlib.h`` that actually dereference the pointers and -call ``hash_eat`` on the instances pointed to. +call ``hash_into`` on the instances pointed to. ``hash_ops`` is also specialized for simple compound types like -``std::pair`` by calling hash_eat in sequence on its members. For flexible +``std::pair`` by calling hash_into in sequence on its members. For flexible size containers like ``std::vector`` the size of the container is hashed first. That is also how implementing hashing for a custom record data type should be - unless there is strong reason to do otherwise, call ``h.eat(m)`` on @@ -143,7 +143,7 @@ based on the existance and value of `YS_HASHING_VERSION`. return mkhash(a, b); } #elif YS_HASHING_VERSION == 1 - Hasher T::hash_eat(Hasher h) const { + Hasher T::hash_into(Hasher h) const { h.eat(a); h.eat(b); return h; diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 47221903481..f7f087080ba 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -177,7 +177,7 @@ namespace AST { // for dict<> and pool<> unsigned int hashidx_; - Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } + Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } // this nodes type AstNodeType type; diff --git a/kernel/bitpattern.h b/kernel/bitpattern.h index 7752acc4297..a9dc98a3348 100644 --- a/kernel/bitpattern.h +++ b/kernel/bitpattern.h @@ -43,7 +43,7 @@ struct BitPatternPool return false; return bitdata == other.bitdata; } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { if (!cached_hash) cached_hash = run_hash(bitdata); h.eat(cached_hash); diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc index 63bbbca3704..fd3c7bb67cd 100644 --- a/kernel/cellaigs.cc +++ b/kernel/cellaigs.cc @@ -39,7 +39,7 @@ bool AigNode::operator==(const AigNode &other) const return true; } -Hasher AigNode::hash_eat(Hasher h) const +Hasher AigNode::hash_into(Hasher h) const { h.eat(portname); h.eat(portbit); @@ -54,7 +54,7 @@ bool Aig::operator==(const Aig &other) const return name == other.name; } -Hasher Aig::hash_eat(Hasher h) const +Hasher Aig::hash_into(Hasher h) const { h.eat(name); return h; diff --git a/kernel/cellaigs.h b/kernel/cellaigs.h index 8d3f0312002..dd1b6dde650 100644 --- a/kernel/cellaigs.h +++ b/kernel/cellaigs.h @@ -34,7 +34,7 @@ struct AigNode AigNode(); bool operator==(const AigNode &other) const; - Hasher hash_eat(Hasher h) const; + Hasher hash_into(Hasher h) const; }; struct Aig @@ -44,7 +44,7 @@ struct Aig Aig(Cell *cell); bool operator==(const Aig &other) const; - Hasher hash_eat(Hasher h) const; + Hasher hash_into(Hasher h) const; }; YOSYS_NAMESPACE_END diff --git a/kernel/drivertools.h b/kernel/drivertools.h index b46c1e2b60a..19c9c2e34d4 100644 --- a/kernel/drivertools.h +++ b/kernel/drivertools.h @@ -74,7 +74,7 @@ struct DriveBitWire return offset < other.offset; } - Hasher hash_eat(Hasher h) const; + Hasher hash_into(Hasher h) const; operator SigBit() const @@ -105,7 +105,7 @@ struct DriveBitPort return offset < other.offset; } - Hasher hash_eat(Hasher h) const; + Hasher hash_into(Hasher h) const; }; @@ -129,7 +129,7 @@ struct DriveBitMarker return offset < other.offset; } - Hasher hash_eat(Hasher h) const; + Hasher hash_into(Hasher h) const; }; @@ -164,7 +164,7 @@ struct DriveBitMultiple return multiple_ == other.multiple_; } - Hasher hash_eat(Hasher h) const; + Hasher hash_into(Hasher h) const; }; struct DriveBit @@ -352,7 +352,7 @@ struct DriveBit return *this; } - Hasher hash_eat(Hasher h) const; + Hasher hash_into(Hasher h) const; bool operator==(const DriveBit &other) const { @@ -473,7 +473,7 @@ struct DriveChunkWire return offset < other.offset; } - Hasher hash_eat(Hasher h) const; + Hasher hash_into(Hasher h) const; explicit operator SigChunk() const { @@ -531,7 +531,7 @@ struct DriveChunkPort return offset < other.offset; } - Hasher hash_eat(Hasher h) const; + Hasher hash_into(Hasher h) const; }; @@ -572,7 +572,7 @@ struct DriveChunkMarker return offset < other.offset; } - Hasher hash_eat(Hasher h) const; + Hasher hash_into(Hasher h) const; }; struct DriveChunkMultiple @@ -612,7 +612,7 @@ struct DriveChunkMultiple return false; // TODO implement, canonicalize order } - Hasher hash_eat(Hasher h) const; + Hasher hash_into(Hasher h) const; }; struct DriveChunk @@ -863,7 +863,7 @@ struct DriveChunk bool try_append(DriveBit const &bit); bool try_append(DriveChunk const &chunk); - Hasher hash_eat(Hasher h) const; + Hasher hash_into(Hasher h) const; bool operator==(const DriveChunk &other) const { @@ -1073,7 +1073,7 @@ struct DriveSpec that->hash_ |= (that->hash_ == 0); } - Hasher hash_eat(Hasher h) const; + Hasher hash_into(Hasher h) const; bool operator==(DriveSpec const &other) const { updhash(); @@ -1112,7 +1112,7 @@ struct DriverMap 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; } - Hasher hash_eat(Hasher h) const; + Hasher hash_into(Hasher h) const; }; // Essentially a dict> but using less memory // and fewer allocations @@ -1258,14 +1258,14 @@ struct DriverMap } }; -inline Hasher DriveBitWire::hash_eat(Hasher h) const +inline Hasher DriveBitWire::hash_into(Hasher h) const { h.eat(wire->name); h.eat(offset); return h; } -inline Hasher DriveBitPort::hash_eat(Hasher h) const +inline Hasher DriveBitPort::hash_into(Hasher h) const { h.eat(cell->name); h.eat(port); @@ -1273,20 +1273,20 @@ inline Hasher DriveBitPort::hash_eat(Hasher h) const return h; } -inline Hasher DriveBitMarker::hash_eat(Hasher h) const +inline Hasher DriveBitMarker::hash_into(Hasher h) const { h.eat(marker); h.eat(offset); return h; } -inline Hasher DriveBitMultiple::hash_eat(Hasher h) const +inline Hasher DriveBitMultiple::hash_into(Hasher h) const { h.eat(multiple_); return h; } -inline Hasher DriveBit::hash_eat(Hasher h) const +inline Hasher DriveBit::hash_into(Hasher h) const { switch (type_) { case DriveType::NONE: @@ -1312,7 +1312,7 @@ inline Hasher DriveBit::hash_eat(Hasher h) const return h; } -inline Hasher DriveChunkWire::hash_eat(Hasher h) const +inline Hasher DriveChunkWire::hash_into(Hasher h) const { h.eat(wire->name); h.eat(width); @@ -1320,7 +1320,7 @@ inline Hasher DriveChunkWire::hash_eat(Hasher h) const return h; } -inline Hasher DriveChunkPort::hash_eat(Hasher h) const +inline Hasher DriveChunkPort::hash_into(Hasher h) const { h.eat(cell->name); h.eat(port); @@ -1329,7 +1329,7 @@ inline Hasher DriveChunkPort::hash_eat(Hasher h) const return h; } -inline Hasher DriveChunkMarker::hash_eat(Hasher h) const +inline Hasher DriveChunkMarker::hash_into(Hasher h) const { h.eat(marker); h.eat(width); @@ -1337,14 +1337,14 @@ inline Hasher DriveChunkMarker::hash_eat(Hasher h) const return h; } -inline Hasher DriveChunkMultiple::hash_eat(Hasher h) const +inline Hasher DriveChunkMultiple::hash_into(Hasher h) const { h.eat(width_); h.eat(multiple_); return h; } -inline Hasher DriveChunk::hash_eat(Hasher h) const +inline Hasher DriveChunk::hash_into(Hasher h) const { switch (type_) { case DriveType::NONE: @@ -1370,7 +1370,7 @@ inline Hasher DriveChunk::hash_eat(Hasher h) const return h; } -inline Hasher DriveSpec::hash_eat(Hasher h) const +inline Hasher DriveSpec::hash_into(Hasher h) const { if (hash_ == 0) updhash(); @@ -1379,7 +1379,7 @@ inline Hasher DriveSpec::hash_eat(Hasher h) const return h; } -inline Hasher DriverMap::DriveBitId::hash_eat(Hasher h) const +inline Hasher DriverMap::DriveBitId::hash_into(Hasher h) const { h.eat(id); return h; diff --git a/kernel/functional.h b/kernel/functional.h index 790190e08ae..e132821405b 100644 --- a/kernel/functional.h +++ b/kernel/functional.h @@ -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; } - Hasher hash_eat(Hasher h) const { h.eat(_v); return h; } + Hasher hash_into(Hasher h) const { h.eat(_v); return h; } }; class IR; class Factory; @@ -225,7 +225,7 @@ namespace Functional { const RTLIL::Const &as_const() const { return std::get(_extra); } std::pair as_idstring_pair() const { return std::get>(_extra); } int as_int() const { return std::get(_extra); } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat((unsigned int) _fn); h.eat(_extra); return h; diff --git a/kernel/hashlib.h b/kernel/hashlib.h index f9271bd7f86..5b1a2a877d3 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -128,12 +128,12 @@ class HasherDJB32 { template void eat(T&& t) { - *this = hash_ops>>::hash_eat(std::forward(t), *this); + *this = hash_ops>>::hash_into(std::forward(t), *this); } template void eat(const T& t) { - *this = hash_ops::hash_eat(t, *this); + *this = hash_ops::hash_into(t, *this); } void commutative_eat(hash_t t) { @@ -153,7 +153,7 @@ struct hash_top_ops { return hash_ops::cmp(a, b); } static inline Hasher hash(const T &a) { - return hash_ops::hash_eat(a, Hasher()); + return hash_ops::hash_into(a, Hasher()); } }; @@ -162,7 +162,7 @@ struct hash_ops { static inline bool cmp(const T &a, const T &b) { return a == b; } - static inline Hasher hash_eat(const T &a, Hasher h) { + static inline Hasher hash_into(const T &a, Hasher h) { if constexpr (std::is_same_v) { h.hash32(a ? 1 : 0); return h; @@ -175,15 +175,15 @@ struct hash_ops { return h; } else if constexpr (std::is_enum_v) { using u_type = std::underlying_type_t; - return hash_ops::hash_eat((u_type) a, h); + return hash_ops::hash_into((u_type) a, h); } else if constexpr (std::is_pointer_v) { - return hash_ops::hash_eat((uintptr_t) a, h); + return hash_ops::hash_into((uintptr_t) a, h); } else if constexpr (std::is_same_v) { for (auto c : a) h.hash32(c); return h; } else { - return a.hash_eat(h); + return a.hash_into(h); } } }; @@ -192,9 +192,9 @@ template struct hash_ops> { static inline bool cmp(std::pair a, std::pair b) { return a == b; } - static inline Hasher hash_eat(std::pair a, Hasher h) { - h = hash_ops

::hash_eat(a.first, h); - h = hash_ops::hash_eat(a.second, h); + static inline Hasher hash_into(std::pair a, Hasher h) { + h = hash_ops

::hash_into(a.first, h); + h = hash_ops::hash_into(a.second, h); return h; } }; @@ -204,14 +204,14 @@ template struct hash_ops> { return a == b; } template - static inline typename std::enable_if::type hash_eat(std::tuple, Hasher h) { + static inline typename std::enable_if::type hash_into(std::tuple, Hasher h) { return h; } template - static inline typename std::enable_if::type hash_eat(std::tuple a, Hasher h) { + static inline typename std::enable_if::type hash_into(std::tuple a, Hasher h) { typedef hash_ops>::type> element_ops_t; - h = hash_eat(a, h); - h = element_ops_t::hash_eat(std::get(a), h); + h = hash_into(a, h); + h = element_ops_t::hash_into(std::get(a), h); return h; } }; @@ -220,7 +220,7 @@ template struct hash_ops> { static inline bool cmp(std::vector a, std::vector b) { return a == b; } - static inline Hasher hash_eat(std::vector a, Hasher h) { + static inline Hasher hash_into(std::vector a, Hasher h) { h.eat(a.size()); for (auto k : a) h.eat(k); @@ -232,9 +232,9 @@ template struct hash_ops> { static inline bool cmp(std::array a, std::array b) { return a == b; } - static inline Hasher hash_eat(std::array a, Hasher h) { + static inline Hasher hash_into(std::array a, Hasher h) { for (const auto& k : a) - h = hash_ops::hash_eat(k, h); + h = hash_ops::hash_into(k, h); return h; } }; @@ -246,7 +246,7 @@ struct hash_cstr_ops { return false; return true; } - static inline Hasher hash_eat(const char *a, Hasher h) { + static inline Hasher hash_into(const char *a, Hasher h) { while (*a) h.hash32(*(a++)); return h; @@ -259,8 +259,8 @@ struct hash_ptr_ops { static inline bool cmp(const void *a, const void *b) { return a == b; } - static inline Hasher hash_eat(const void *a, Hasher h) { - return hash_ops::hash_eat((uintptr_t)a, h); + static inline Hasher hash_into(const void *a, Hasher h) { + return hash_ops::hash_into((uintptr_t)a, h); } }; @@ -269,8 +269,8 @@ struct hash_obj_ops { return a == b; } template - static inline Hasher hash_eat(const T *a, Hasher h) { - return a ? a->hash_eat(h) : h; + static inline Hasher hash_into(const T *a, Hasher h) { + return a ? a->hash_into(h) : h; } }; /** @@ -297,7 +297,7 @@ template<> struct hash_ops { static inline bool cmp(std::monostate a, std::monostate b) { return a == b; } - static inline Hasher hash_eat(std::monostate, Hasher h) { + static inline Hasher hash_into(std::monostate, Hasher h) { return h; } }; @@ -306,7 +306,7 @@ template struct hash_ops> { static inline bool cmp(std::variant a, std::variant b) { return a == b; } - static inline Hasher hash_eat(std::variant a, Hasher h) { + static inline Hasher hash_into(std::variant a, Hasher h) { std::visit([& h](const auto &v) { h.eat(v); }, a); h.eat(a.index()); return h; @@ -317,7 +317,7 @@ template struct hash_ops> { static inline bool cmp(std::optional a, std::optional b) { return a == b; } - static inline Hasher hash_eat(std::optional a, Hasher h) { + static inline Hasher hash_into(std::optional a, Hasher h) { if(a.has_value()) h.eat(*a); else @@ -790,7 +790,7 @@ class dict { return !operator==(other); } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(entries.size()); for (auto &it : entries) { Hasher entry_hash; @@ -1160,7 +1160,7 @@ class pool return !operator==(other); } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(entries.size()); for (auto &it : entries) { h.commutative_eat(ops.hash(it.udata).yield()); diff --git a/kernel/modtools.h b/kernel/modtools.h index fce22d8579d..0ed858e3739 100644 --- a/kernel/modtools.h +++ b/kernel/modtools.h @@ -48,7 +48,7 @@ struct ModIndex : public RTLIL::Monitor return cell == other.cell && port == other.port && offset == other.offset; } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(cell->name); h.eat(port); h.eat(offset); @@ -324,7 +324,7 @@ struct ModWalker return cell == other.cell && port == other.port && offset == other.offset; } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(cell->name); h.eat(port); h.eat(offset); diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 2b3d274a2e9..0f4bec7b065 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -362,7 +362,7 @@ struct RTLIL::IdString *this = IdString(); } - Hasher hash_eat(Hasher h) const { return hash_ops::hash_eat(index_, h); } + Hasher hash_into(Hasher h) const { return hash_ops::hash_into(index_, h); } Hasher hash_top() const { Hasher h; @@ -815,7 +815,7 @@ struct RTLIL::Const bv.resize(width, bv.empty() ? RTLIL::State::Sx : bv.back()); } - inline Hasher hash_eat(Hasher h) const { + inline Hasher hash_into(Hasher h) const { // TODO hash size for (auto b : *this) h.eat(b); @@ -908,7 +908,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; - Hasher hash_eat(Hasher h) const; + Hasher hash_into(Hasher h) const; Hasher hash_top() const; }; @@ -1115,7 +1115,7 @@ struct RTLIL::SigSpec operator std::vector() const { return bits(); } const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; } - Hasher hash_eat(Hasher h) const { if (!hash_) updhash(); h.eat(hash_); return h; } + Hasher hash_into(Hasher h) const { if (!hash_) updhash(); h.eat(hash_); return h; } #ifndef NDEBUG void check(Module *mod = nullptr) const; @@ -1157,7 +1157,7 @@ struct RTLIL::Selection struct RTLIL::Monitor { Hasher::hash_t hashidx_; - Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } + Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } Monitor() { static unsigned int hashidx_count = 123456789; @@ -1180,7 +1180,7 @@ struct define_map_t; struct RTLIL::Design { Hasher::hash_t hashidx_; - Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } + Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } pool monitors; dict scratchpad; @@ -1285,7 +1285,7 @@ struct RTLIL::Design struct RTLIL::Module : public RTLIL::AttrObject { Hasher::hash_t hashidx_; - Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } + Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } protected: void add(RTLIL::Wire *wire); @@ -1640,7 +1640,7 @@ void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire); struct RTLIL::Wire : public RTLIL::AttrObject { Hasher::hash_t hashidx_; - Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } + Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } protected: // use module->addWire() and module->remove() to create or destroy wires @@ -1679,7 +1679,7 @@ inline int GetSize(RTLIL::Wire *wire) { struct RTLIL::Memory : public RTLIL::AttrObject { Hasher::hash_t hashidx_; - Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } + Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } Memory(); @@ -1694,7 +1694,7 @@ struct RTLIL::Memory : public RTLIL::AttrObject struct RTLIL::Cell : public RTLIL::AttrObject { Hasher::hash_t hashidx_; - Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } + Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } protected: // use module->addCell() and module->remove() to create or destroy cells @@ -1804,7 +1804,7 @@ struct RTLIL::SyncRule struct RTLIL::Process : public RTLIL::AttrObject { Hasher::hash_t hashidx_; - Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } + Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } protected: // use module->addProcess() and module->remove() to create or destroy processes @@ -1848,7 +1848,7 @@ inline bool RTLIL::SigBit::operator!=(const RTLIL::SigBit &other) const { return (wire != other.wire) || (wire ? (offset != other.offset) : (data != other.data)); } -inline Hasher RTLIL::SigBit::hash_eat(Hasher h) const { +inline Hasher RTLIL::SigBit::hash_into(Hasher h) const { if (wire) { h.eat(offset); h.eat(wire->name); diff --git a/kernel/scopeinfo.h b/kernel/scopeinfo.h index 3c9ca69b690..f3ae0d7b682 100644 --- a/kernel/scopeinfo.h +++ b/kernel/scopeinfo.h @@ -169,7 +169,7 @@ class IdTree return !(*this == other); } - Hasher hash_acc(Hasher h) const + Hasher hash_into(Hasher h) const { h.eat(scope_name); h.eat(target); @@ -325,7 +325,7 @@ struct ModuleItem { Cell *cell() const { return type == Type::Cell ? static_cast(ptr) : nullptr; } bool operator==(const ModuleItem &other) const { return ptr == other.ptr && type == other.type; } - Hasher hash_eat(Hasher h) const { h.eat(ptr); return h; } + Hasher hash_into(Hasher h) const { h.eat(ptr); return h; } }; static inline void log_dump_val_worker(typename IdTree::Cursor cursor ) { log("%p %s", cursor.target, log_id(cursor.scope_name)); } diff --git a/kernel/sigtools.h b/kernel/sigtools.h index c827807aadb..a22685ee2c3 100644 --- a/kernel/sigtools.h +++ b/kernel/sigtools.h @@ -29,7 +29,7 @@ struct SigPool struct bitDef_t : public std::pair { bitDef_t() : std::pair(NULL, 0) { } bitDef_t(const RTLIL::SigBit &bit) : std::pair(bit.wire, bit.offset) { } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(first->name); h.eat(second); return h; @@ -147,7 +147,7 @@ struct SigSet struct bitDef_t : public std::pair { bitDef_t() : std::pair(NULL, 0) { } bitDef_t(const RTLIL::SigBit &bit) : std::pair(bit.wire, bit.offset) { } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(first->name); h.eat(second); return h; diff --git a/kernel/timinginfo.h b/kernel/timinginfo.h index e294d29a7e5..677bbecb85d 100644 --- a/kernel/timinginfo.h +++ b/kernel/timinginfo.h @@ -44,7 +44,7 @@ struct TimingInfo return {}; return port[offset]; } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(name); h.eat(offset); return h; @@ -56,7 +56,7 @@ 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; } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(first); h.eat(second); return h; diff --git a/kernel/yosys_common.h b/kernel/yosys_common.h index b194718f113..e0bd91ec897 100644 --- a/kernel/yosys_common.h +++ b/kernel/yosys_common.h @@ -171,7 +171,7 @@ 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; } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(*content); return h; } diff --git a/kernel/yw.h b/kernel/yw.h index e16d4986609..34546d1e246 100644 --- a/kernel/yw.h +++ b/kernel/yw.h @@ -35,7 +35,7 @@ struct IdPath : public std::vector bool has_address() const { int tmp; return get_address(tmp); }; bool get_address(int &addr) const; - Hasher hash_eat(Hasher h) const { h.eat(*this); return h; } + Hasher hash_into(Hasher h) const { h.eat(*this); return h; } }; struct WitnessHierarchyItem { diff --git a/passes/cmds/dft_tag.cc b/passes/cmds/dft_tag.cc index 2a5fb690efb..cecab4d61da 100644 --- a/passes/cmds/dft_tag.cc +++ b/passes/cmds/dft_tag.cc @@ -47,7 +47,7 @@ struct DftTagWorker { bool operator<(const tag_set &other) const { return index < other.index; } bool operator==(const tag_set &other) const { return index == other.index; } - Hasher hash_eat(Hasher h) const { h.eat(index); return h; } + Hasher hash_into(Hasher h) const { h.eat(index); return h; } bool empty() const { return index == 0; } }; diff --git a/passes/cmds/example_dt.cc b/passes/cmds/example_dt.cc index 7cd1d2f24a5..5f5246de67b 100644 --- a/passes/cmds/example_dt.cc +++ b/passes/cmds/example_dt.cc @@ -52,7 +52,7 @@ struct ExampleDtPass : public Pass return name == other.name && parameters == other.parameters; } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(name); h.eat(parameters); return h; diff --git a/passes/equiv/equiv_struct.cc b/passes/equiv/equiv_struct.cc index 774c5a1a607..195cb342448 100644 --- a/passes/equiv/equiv_struct.cc +++ b/passes/equiv/equiv_struct.cc @@ -46,7 +46,7 @@ struct EquivStructWorker parameters == other.parameters && port_sizes == other.port_sizes; } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(type); h.eat(parameters); h.eat(port_sizes); diff --git a/passes/proc/proc_dlatch.cc b/passes/proc/proc_dlatch.cc index 6b579b4e4cc..2e41afd09c6 100644 --- a/passes/proc/proc_dlatch.cc +++ b/passes/proc/proc_dlatch.cc @@ -127,7 +127,7 @@ struct proc_dlatch_db_t return signal == other.signal && match == other.match && children == other.children; } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(signal); h.eat(match); h.eat(children); diff --git a/passes/sat/recover_names.cc b/passes/sat/recover_names.cc index a84380cbf5c..c18beafa1ee 100644 --- a/passes/sat/recover_names.cc +++ b/passes/sat/recover_names.cc @@ -46,7 +46,7 @@ struct IdBit { bool operator==(const IdBit &other) const { return name == other.name && bit == other.bit; }; bool operator!=(const IdBit &other) const { return name != other.name || bit != other.bit; }; - Hasher hash_eat(Hasher h) const + Hasher hash_into(Hasher h) const { h.eat(name); h.eat(bit); @@ -64,7 +64,7 @@ struct InvBit { bool operator==(const InvBit &other) const { return bit == other.bit && inverted == other.inverted; }; bool operator!=(const InvBit &other) const { return bit != other.bit || inverted != other.inverted; }; - Hasher hash_eat(Hasher h) const + Hasher hash_into(Hasher h) const { h.eat(bit); h.eat(inverted); diff --git a/passes/techmap/clockgate.cc b/passes/techmap/clockgate.cc index bfd4c8a9724..bdfb94170d8 100644 --- a/passes/techmap/clockgate.cc +++ b/passes/techmap/clockgate.cc @@ -233,7 +233,7 @@ struct ClockgatePass : public Pass { SigBit ce_bit; bool pol_clk; bool pol_ce; - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { auto t = std::make_tuple(clk_bit, ce_bit, pol_clk, pol_ce); h.eat(t); return h; diff --git a/passes/techmap/flowmap.cc b/passes/techmap/flowmap.cc index bfee38999cc..00d5369e4e0 100644 --- a/passes/techmap/flowmap.cc +++ b/passes/techmap/flowmap.cc @@ -250,7 +250,7 @@ struct FlowGraph { return !(*this == other); } - Hasher hash_eat(Hasher h) const + Hasher hash_into(Hasher h) const { std::pair p = {node, is_bottom}; h.eat(p); diff --git a/techlibs/quicklogic/ql_dsp_simd.cc b/techlibs/quicklogic/ql_dsp_simd.cc index 162f0c2d683..bda7fb3bd24 100644 --- a/techlibs/quicklogic/ql_dsp_simd.cc +++ b/techlibs/quicklogic/ql_dsp_simd.cc @@ -53,7 +53,7 @@ struct QlDspSimdPass : public Pass { DspConfig(const DspConfig &ref) = default; DspConfig(DspConfig &&ref) = default; - Hasher hash_eat(Hasher h) const { h.eat(connections); return h; } + Hasher hash_into(Hasher h) const { h.eat(connections); return h; } bool operator==(const DspConfig &ref) const { return connections == ref.connections; } }; From ed70038aa1472197f71f0a69835a830a5970fff0 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 20 Nov 2024 12:11:37 +0100 Subject: [PATCH 25/26] hashlib: fixes from jix --- kernel/drivertools.h | 11 +++++------ kernel/hashlib.h | 14 ++++---------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/kernel/drivertools.h b/kernel/drivertools.h index 19c9c2e34d4..e584f4d39cb 100644 --- a/kernel/drivertools.h +++ b/kernel/drivertools.h @@ -1067,10 +1067,11 @@ struct DriveSpec DriveSpec &operator=(DriveBitMultiple const &bit) { return *this = DriveBit(bit); } void updhash() const { - DriveSpec *that = (DriveSpec*)this; + if (hash_ != 0) + return; pack(); - that->hash_ = run_hash(chunks_); - that->hash_ |= (that->hash_ == 0); + hash_ = run_hash(chunks_); + hash_ |= (hash_ == 0); } Hasher hash_into(Hasher h) const; @@ -1372,9 +1373,7 @@ inline Hasher DriveChunk::hash_into(Hasher h) const inline Hasher DriveSpec::hash_into(Hasher h) const { - if (hash_ == 0) - updhash(); - + updhash(); h.eat(hash_); return h; } diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 5b1a2a877d3..0e712a2a35c 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -116,7 +116,7 @@ class HasherDJB32 { return; } void hash64(uint64_t i) { - state = djb2_xor((uint32_t)(i % (1ULL << 32ULL)), state); + state = djb2_xor((uint32_t)(i & 0xFFFFFFFFULL), state); state = djb2_xor((uint32_t)(i >> 32ULL), state); state = mkhash_xorshift(fudge ^ state); return; @@ -163,10 +163,7 @@ struct hash_ops { return a == b; } static inline Hasher hash_into(const T &a, Hasher h) { - if constexpr (std::is_same_v) { - h.hash32(a ? 1 : 0); - return h; - } else if constexpr (std::is_integral_v) { + if constexpr (std::is_integral_v) { static_assert(sizeof(T) <= sizeof(uint64_t)); if (sizeof(T) == sizeof(uint64_t)) h.hash64(a); @@ -221,7 +218,7 @@ template struct hash_ops> { return a == b; } static inline Hasher hash_into(std::vector a, Hasher h) { - h.eat(a.size()); + h.eat((uint32_t)a.size()); for (auto k : a) h.eat(k); return h; @@ -241,10 +238,7 @@ template struct hash_ops> { struct hash_cstr_ops { static inline bool cmp(const char *a, const char *b) { - for (int i = 0; a[i] || b[i]; i++) - if (a[i] != b[i]) - return false; - return true; + return strcmp(a, b) == 0; } static inline Hasher hash_into(const char *a, Hasher h) { while (*a) From 026e9dae9d7a2c2e4ce90a6125c0d57922f6a8de Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 20 Nov 2024 17:06:49 +0100 Subject: [PATCH 26/26] hashlib: fixes from jix --- kernel/drivertools.h | 1 - kernel/hashlib.h | 10 +++++++--- kernel/modtools.h | 3 --- kernel/rtlil.h | 16 ++++++++-------- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/kernel/drivertools.h b/kernel/drivertools.h index e584f4d39cb..23eba9f1c05 100644 --- a/kernel/drivertools.h +++ b/kernel/drivertools.h @@ -1112,7 +1112,6 @@ struct DriverMap 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; } Hasher hash_into(Hasher h) const; }; // Essentially a dict> but using less memory diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 0e712a2a35c..6927702e156 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -264,7 +264,11 @@ struct hash_obj_ops { } template static inline Hasher hash_into(const T *a, Hasher h) { - return a ? a->hash_into(h) : h; + if (a) + a->hash_into(h); + else + h.eat(0); + return h; } }; /** @@ -785,13 +789,13 @@ class dict { } Hasher hash_into(Hasher h) const { - h.eat(entries.size()); for (auto &it : entries) { Hasher entry_hash; entry_hash.eat(it.udata.first); entry_hash.eat(it.udata.second); h.commutative_eat(entry_hash.yield()); } + h.eat(entries.size()); return h; } @@ -1155,10 +1159,10 @@ class pool } Hasher hash_into(Hasher h) const { - h.eat(entries.size()); for (auto &it : entries) { h.commutative_eat(ops.hash(it.udata).yield()); } + h.eat(entries.size()); return h; } diff --git a/kernel/modtools.h b/kernel/modtools.h index 0ed858e3739..921df304ca2 100644 --- a/kernel/modtools.h +++ b/kernel/modtools.h @@ -60,8 +60,6 @@ struct ModIndex : public RTLIL::Monitor { bool is_input, is_output; pool ports; - // SigBitInfo() : SigBitInfo{} {} - // SigBitInfo& operator=(const SigBitInfo&) = default; SigBitInfo() : is_input(false), is_output(false) { } @@ -310,7 +308,6 @@ struct ModWalker 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) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 0f4bec7b065..330af649f74 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -408,8 +408,14 @@ namespace hashlib { }; }; -// TODO deprecate this +/** + * How to not use these methods: + * 1. if(celltype.in({...})) -> if(celltype.in(...)) + * 2. pool p; ... a.in(p) -> (bool)p.count(a) + */ +[[deprecated]] inline bool RTLIL::IdString::in(const pool &rhs) const { return rhs.count(*this) != 0; } +[[deprecated]] inline bool RTLIL::IdString::in(const pool &&rhs) const { return rhs.count(*this) != 0; } namespace RTLIL { @@ -816,7 +822,7 @@ struct RTLIL::Const } inline Hasher hash_into(Hasher h) const { - // TODO hash size + h.eat(size()); for (auto b : *this) h.eat(b); return h; @@ -1003,12 +1009,6 @@ struct RTLIL::SigSpec SigSpec(const std::set &bits); explicit SigSpec(bool bit); - [[deprecated]] - size_t get_hash() const { - log_assert(false && "deprecated"); - return 0; - } - inline const std::vector &chunks() const { pack(); return chunks_; } inline const std::vector &bits() const { inline_unpack(); return bits_; }