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 | 303 +++++++++++++++----------- 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, 542 insertions(+), 386 deletions(-) diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index b72caf119..931454ada 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 f163dff9e..0882ba804 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 bdff015e3..1a72e6285 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 d39030c2d..8f1b07b10 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 3c77dd7c3..4e9c7a305 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 ef8247e83..860d3c166 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 c1ceac14c..3814f4672 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 de0a49394..81b486c79 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 8f6d69ba6..bdb8b3c07 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 8929c3426..fdead5c36 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 @@ public: return multiple_ == other.multiple_; } - unsigned int hash() const - { - return multiple_.hash(); - } + Hasher hash_acc(Hasher h) const; }; struct DriveBit @@ -362,35 +352,7 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: } 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 @@ public: DriveSpec &operator=(DriveBitMarker const &bit) { return *this = DriveBit(bit); } DriveSpec &operator=(DriveBitMultiple const &bit) { return *this = DriveBit(bit); } - unsigned int hash() const { - if (hash_ != 0) return hash_; - + void updhash() const { + DriveSpec *that = (DriveSpec*)this; pack(); - hash_ = hash_ops>().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 @@ private: bool operator==(const DriveBitId &other) const { return id == other.id; } bool operator!=(const DriveBitId &other) const { return id != other.id; } bool operator<(const DriveBitId &other) const { return id < other.id; } - unsigned int hash() const { return id; } + // unsigned int hash() const { return id; } + Hasher hash_acc(Hasher h) const; }; // Essentially a dict> but using less memory // and fewer allocations @@ -1333,6 +1290,133 @@ private: } }; +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 61b303e0b..b80c77be4 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 859115829..21e4e155b 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 { +class Hasher { + public: //TODO + using hash_t = uint32_t; + + Hasher() { + // traditionally 5381 is used as starting value for the djb2 hash + state = 5381; + } + + private: + uint32_t state; + // The XOR version of DJB2 + [[nodiscard]] + static uint32_t mkhash(uint32_t a, uint32_t b) { + return ((a << 5) + a) ^ b; + } + public: + void hash32(uint32_t i) { + state = mkhash(i, state); + return; + } + void hash64(uint64_t i) { + state = mkhash((uint32_t)(i % (1ULL << 32ULL)), state); + state = mkhash((uint32_t)(i >> 32ULL), state); + return; + } + hash_t yield() { + return (hash_t)state; + } + + template + 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 T &a, const T &b) { return a == b; } - static inline unsigned int hash(const T &a) { - return a.hash(); - } -}; - -struct hash_int_ops { - template - static inline bool cmp(T a, T b) { - return a == b; - } -}; - -template<> struct hash_ops : hash_int_ops -{ - static inline unsigned int hash(bool a) { - return a ? 1 : 0; - } -}; -template<> struct hash_ops : hash_int_ops -{ - static inline unsigned int hash(int32_t a) { - return a; - } -}; -template<> struct hash_ops : hash_int_ops -{ - static inline unsigned int hash(int64_t a) { - return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); - } -}; -template<> struct hash_ops : hash_int_ops -{ - static inline unsigned int hash(uint32_t a) { - return a; - } -}; -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<> struct hash_ops { - static inline bool cmp(const std::string &a, const std::string &b) { - return a == b; - } - static inline unsigned int hash(const std::string &a) { - unsigned int v = 0; - for (auto c : a) - v = mkhash(v, c); - return v; + static inline Hasher hash_acc(const T &a, Hasher h) { + if constexpr (std::is_same_v) { + 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 @@ public: 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 @@ public: 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 @@ protected: std::vector hashtable; std::vector entries; - OPS ops; + hash_ops ops; #ifdef NDEBUG static inline void do_assert(bool) { } @@ -736,9 +792,9 @@ protected: int do_hash(const K &key) const { - unsigned int hash = 0; + Hasher::hash_t hash = 0; if (!hashtable.empty()) - hash = ops.hash(key) % (unsigned int)(hashtable.size()); + hash = run_hash(key) % (unsigned int)(hashtable.size()); return hash; } @@ -1051,11 +1107,12 @@ public: return !operator==(other); } - unsigned int hash() const { - unsigned int hashval = mkhash_init; - for (auto &it : entries) - hashval ^= ops.hash(it.udata); - return hashval; + Hasher hash_acc(Hasher h) const { + h.acc(entries.size()); + for (auto &it : entries) { + h.commutative_acc(run_hash(it.udata)); + } + return h; } void reserve(size_t n) { entries.reserve(n); } @@ -1072,10 +1129,10 @@ public: 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 @@ public: * 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 4b90cf9dc..e26ef072c 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 34a23b379..1afa0ad50 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 b279cce6e..65510362e 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 6d3558621..a1f8668d0 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 @@ public: 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 @@ public: 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 @@ public: 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 8c6e99fc0..5d2e6d4b1 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 63f1b51ec..f3779c37c 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 8eb7eb738..373615f59 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 99f327db4..07edad074 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 @@ public: current_state.erase(k); } - const dict &stdmap() + const dict &stdmap() { return current_state; } @@ -128,7 +128,7 @@ public: // 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 29dcd58c5..52f7f5f96 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 c2f5921b1..a4bae5515 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 8947570e7..0b1127a11 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 1912d7da1..97ce26327 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 3655f3f49..9dd68bd00 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 39604994a..55b364971 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 5b392ce51..5936502c0 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 b209057fe..2f539c960 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 02174be53..3075ef3f0 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 4870e2cac..05ddf8e55 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 c3fa213f6..8fac93b98 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 e4e70004c..05a3d1702 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 44fdc7e47..79c1be7c1 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 b5b951323..b07097b99 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 b42823d8b..bcbb290df 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 6565c472c..a3d85bd90 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 fdead5c36..0e7b872e4 100644 --- a/kernel/drivertools.h +++ b/kernel/drivertools.h @@ -863,39 +863,7 @@ public: 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 21e4e155b..15c2c1afb 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 5d2e6d4b1..fa550dab6 100644 --- a/kernel/scopeinfo.h +++ b/kernel/scopeinfo.h @@ -169,8 +169,11 @@ public: 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 bdd7303aa..7cf60f068 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 07f9ee45d..cc37677ce 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 15c2c1afb..2e4c49176 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 c62e624d2..03374c610 100644 --- a/misc/py_wrap_generator.py +++ b/misc/py_wrap_generator.py @@ -855,7 +855,11 @@ class WClass: 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 @@ class WClass: 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 @@ sources = [ ] ), 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 2e4c49176..b4d82f80a 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 52f7f5f96..9370de330 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 3f8d807b3..fe8b4a444 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 b4d82f80a..a1dffdaee 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ protected: } #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 @@ protected: 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 @@ protected: 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 @@ protected: 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 @@ protected: 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 @@ protected: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 a1dffdaee..4ed1a5605 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 4ed1a5605..13b53e383 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 13b53e383..33a1e04f8 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 33a1e04f8..aa9f43ff4 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 a1f8668d0..b048b1a44 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 b048b1a44..4f9550478 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 aa9f43ff4..3b33748d3 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 @@ public: 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 @@ protected: std::vector hashtable; std::vector entries; - hash_ops ops; + OPS ops; #ifdef NDEBUG static inline void do_assert(bool) { } @@ -832,7 +856,7 @@ protected: { 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 @@ public: 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 @@ public: 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 @@ public: * 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 4f9550478..afa538540 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 9370de330..954a2a53f 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 | 601 ++++++++++++++++++++++++----------------------- 2 files changed, 314 insertions(+), 313 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 3b33748d3..f1d871632 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 afa538540..b17b82c47 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 +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 + +#ifdef YOSYS_USE_STICKY_IDS + static int last_created_idx_ptr_; + static int last_created_idx_[8]; +#endif + + static inline void xtrace_db_dump() { - #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_; + #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 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; } - 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 - } + 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); - 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 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; - } - - 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); - } - - 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); - } - - #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; + 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); } - #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 - - int &refcount = global_refcount_storage_[idx]; - - if (--refcount > 0) - return; - - 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); - } - - 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); - } + 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 - static inline void put_reference(int) { } + 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 - // the actual IdString object is just is a single int - - int 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 void operator=(const IdString &rhs) { - put_reference(index_); - index_ = get_reference(rhs.index_); + if (yosys_xtrace) { + log("#X# New IdString '%s' with index %d.\n", p, idx); + log_backtrace("-X- ", yosys_xtrace-1); } - inline void operator=(const char *rhs) { - IdString id(rhs); - *this = id; + #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; + } + +#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 + + int &refcount = global_refcount_storage_[idx]; + + if (--refcount > 0) + return; + + 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 std::string &rhs) { - IdString id(rhs); - *this = id; - } - - inline const char *c_str() const { - return global_id_storage_.at(index_); - } - - inline std::string str() const { - return std::string(global_id_storage_.at(index_)); - } - - 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; + 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 - return *(p + i); + static inline void put_reference(int) { } #endif + + // the actual IdString object is just is a single int + + int 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 void operator=(const IdString &rhs) { + put_reference(index_); + index_ = get_reference(rhs.index_); + } + + inline void operator=(const char *rhs) { + IdString id(rhs); + *this = id; + } + + inline void operator=(const std::string &rhs) { + IdString id(rhs); + *this = id; + } + + inline const char *c_str() const { + return global_id_storage_.at(index_); + } + + inline std::string str() const { + return std::string(global_id_storage_.at(index_)); + } + + 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; +#else + 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); + } + + 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 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); + } + + size_t size() const { + return strlen(c_str()); + } + + bool empty() const { + return c_str()[0] == 0; + } + + void clear() { + *this = IdString(); + } + + Hasher hash_acc(Hasher h) const { 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. + + 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); } - - 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); - } - - 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 contains(const char* str) const { - return strstr(c_str(), str); - } - - size_t size() const { - return strlen(c_str()); - } - - bool empty() const { - return c_str()[0] == 0; - } - - 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; - } - - return hash_ops::hash_acc(index_, 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. - - 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. - - 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; } - bool in(const pool &rhs) const { return rhs.count(*this) != 0; } - - bool isPublic() const { return begins_with("\\"); } }; + // 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)); + } + + 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 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 f1d871632..b185eeed4 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 000000000..ba4e08af2 --- /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 b185eeed4..ca2a04cec 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 | 86 +++++++++++++++++++------ docs/source/yosys_internals/index.rst | 1 + 2 files changed, 69 insertions(+), 18 deletions(-) diff --git a/docs/source/yosys_internals/hashing.rst b/docs/source/yosys_internals/hashing.rst index ba4e08af2..32c4453c8 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. +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. +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. +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. +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 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 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``. +``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 9631e8653..3dd4224fa 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 32c4453c8..372be05ec 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 372be05ec..b88bf1223 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 110f63185..17fe32523 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 b88bf1223..0d74f9014 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 ca2a04cec..df6a4853c 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -103,19 +103,19 @@ private: 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 0d74f9014..b6d8df6ef 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 90fa5328c..19ba59f17 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 1a72e6285..472219034 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 3814f4672..7752acc42 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 81b486c79..63bbbca37 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 bdb8b3c07..8d3f03120 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 0e7b872e4..b46c1e2b6 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 @@ public: return multiple_ == other.multiple_; } - Hasher hash_acc(Hasher h) const; + Hasher hash_eat(Hasher h) const; }; struct DriveBit @@ -352,7 +352,7 @@ public: 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 @@ public: return false; // TODO implement, canonicalize order } - Hasher hash_acc(Hasher h) const; + Hasher hash_eat(Hasher h) const; }; struct DriveChunk @@ -863,7 +863,7 @@ public: 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 @@ public: 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 @@ private: 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 @@ private: } }; -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 b80c77be4..790190e08 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 df6a4853c..f66baa429 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -125,16 +125,16 @@ private: } 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 @@ public: 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 @@ public: 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 1afa0ad50..fce22d857 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 65510362e..cb0f7da78 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 b17b82c47..eaf2eaf8e 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 @@ public: 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 @@ public: 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 fa550dab6..3c9ca69b6 100644 --- a/kernel/scopeinfo.h +++ b/kernel/scopeinfo.h @@ -171,8 +171,8 @@ public: 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 f3779c37c..c827807aa 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 373615f59..e294d29a7 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 954a2a53f..b194718f1 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 a4bae5515..e16d49866 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 0b1127a11..2a5fb690e 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 97ce26327..7cd1d2f24 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 55b364971..774c5a1a6 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 5936502c0..6b579b4e4 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 05ddf8e55..a84380cbf 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 79c1be7c1..bfd4c8a97 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 b07097b99..bfee38999 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 bcbb290df..162f0c2d6 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 f66baa429..3be33ebd9 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 eaf2eaf8e..2b3d274a2 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 b6d8df6ef..0e3e5fc90 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 3be33ebd9..f9271bd7f 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 0e3e5fc90..338ee5fd6 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 472219034..f7f087080 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 7752acc42..a9dc98a33 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 63bbbca37..fd3c7bb67 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 8d3f03120..dd1b6dde6 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 b46c1e2b6..19c9c2e34 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 @@ public: return multiple_ == other.multiple_; } - Hasher hash_eat(Hasher h) const; + Hasher hash_into(Hasher h) const; }; struct DriveBit @@ -352,7 +352,7 @@ public: 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 @@ public: return false; // TODO implement, canonicalize order } - Hasher hash_eat(Hasher h) const; + Hasher hash_into(Hasher h) const; }; struct DriveChunk @@ -863,7 +863,7 @@ public: 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 @@ public: 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 @@ private: 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 @@ private: } }; -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 790190e08..e13282140 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 f9271bd7f..5b1a2a877 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -128,12 +128,12 @@ private: 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 @@ public: 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 @@ public: 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 fce22d857..0ed858e37 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 2b3d274a2..0f4bec7b0 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 @@ public: 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 @@ public: 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 3c9ca69b6..f3ae0d7b6 100644 --- a/kernel/scopeinfo.h +++ b/kernel/scopeinfo.h @@ -169,7 +169,7 @@ public: 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 c827807aa..a22685ee2 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 e294d29a7..677bbecb8 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 b194718f1..e0bd91ec8 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 e16d49866..34546d1e2 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 2a5fb690e..cecab4d61 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 7cd1d2f24..5f5246de6 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 774c5a1a6..195cb3424 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 6b579b4e4..2e41afd09 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 a84380cbf..c18beafa1 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 bfd4c8a97..bdfb94170 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 bfee38999..00d5369e4 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 162f0c2d6..bda7fb3bd 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 19c9c2e34..e584f4d39 100644 --- a/kernel/drivertools.h +++ b/kernel/drivertools.h @@ -1067,10 +1067,11 @@ public: 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 5b1a2a877..0e712a2a3 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -116,7 +116,7 @@ private: 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 e584f4d39..23eba9f1c 100644 --- a/kernel/drivertools.h +++ b/kernel/drivertools.h @@ -1112,7 +1112,6 @@ private: bool operator==(const DriveBitId &other) const { return id == other.id; } bool operator!=(const DriveBitId &other) const { return id != other.id; } bool operator<(const DriveBitId &other) const { return id < other.id; } - // unsigned int hash() const { return id; } Hasher hash_into(Hasher h) const; }; // Essentially a dict> but using less memory diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 0e712a2a3..6927702e1 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 @@ public: } 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 @@ public: } 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 0ed858e37..921df304c 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 0f4bec7b0..330af649f 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 @@ public: } 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 @@ public: 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_; }