mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 13:29:12 +00:00 
			
		
		
		
	Sync
This commit is contained in:
		
						commit
						1dcf75d175
					
				
					 68 changed files with 1270 additions and 879 deletions
				
			
		
							
								
								
									
										154
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										154
									
								
								Makefile
									
										
									
									
									
								
							| 
						 | 
					@ -171,7 +171,7 @@ ifeq ($(OS), Haiku)
 | 
				
			||||||
CXXFLAGS += -D_DEFAULT_SOURCE
 | 
					CXXFLAGS += -D_DEFAULT_SOURCE
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
YOSYS_VER := 0.48+5
 | 
					YOSYS_VER := 0.48+45
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Note: We arrange for .gitcommit to contain the (short) commit hash in
 | 
					# Note: We arrange for .gitcommit to contain the (short) commit hash in
 | 
				
			||||||
# tarballs generated with git-archive(1) using .gitattributes. The git repo
 | 
					# tarballs generated with git-archive(1) using .gitattributes. The git repo
 | 
				
			||||||
| 
						 | 
					@ -872,72 +872,100 @@ else
 | 
				
			||||||
ABCOPT=""
 | 
					ABCOPT=""
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# When YOSYS_NOVERIFIC is set as a make variable, also export it to the
 | 
					# Tests that generate .mk with tests/gen-tests-makefile.sh
 | 
				
			||||||
# environment, so that `YOSYS_NOVERIFIC=1 make test` _and_
 | 
					MK_TEST_DIRS =
 | 
				
			||||||
# `make test YOSYS_NOVERIFIC=1` will run with verific disabled.
 | 
					# MK_TEST_DIRS += tests/arch/anlogic
 | 
				
			||||||
ifeq ($(YOSYS_NOVERIFIC),1)
 | 
					# MK_TEST_DIRS += tests/arch/ecp5
 | 
				
			||||||
export YOSYS_NOVERIFIC
 | 
					# MK_TEST_DIRS += tests/arch/efinix
 | 
				
			||||||
 | 
					# MK_TEST_DIRS += tests/arch/gatemate
 | 
				
			||||||
 | 
					# MK_TEST_DIRS += tests/arch/gowin
 | 
				
			||||||
 | 
					# MK_TEST_DIRS += tests/arch/ice40
 | 
				
			||||||
 | 
					# MK_TEST_DIRS += tests/arch/intel_alm
 | 
				
			||||||
 | 
					# MK_TEST_DIRS += tests/arch/machxo2
 | 
				
			||||||
 | 
					# MK_TEST_DIRS += tests/arch/microchip
 | 
				
			||||||
 | 
					# MK_TEST_DIRS += tests/arch/nanoxplore
 | 
				
			||||||
 | 
					# MK_TEST_DIRS += tests/arch/nexus
 | 
				
			||||||
 | 
					# MK_TEST_DIRS += tests/arch/quicklogic/pp3
 | 
				
			||||||
 | 
					# MK_TEST_DIRS += tests/arch/quicklogic/qlf_k6n10f
 | 
				
			||||||
 | 
					# MK_TEST_DIRS += tests/arch/xilinx
 | 
				
			||||||
 | 
					MK_TEST_DIRS += tests/opt
 | 
				
			||||||
 | 
					MK_TEST_DIRS += tests/sat
 | 
				
			||||||
 | 
					MK_TEST_DIRS += tests/sim
 | 
				
			||||||
 | 
					MK_TEST_DIRS += tests/svtypes
 | 
				
			||||||
 | 
					MK_TEST_DIRS += tests/techmap
 | 
				
			||||||
 | 
					MK_TEST_DIRS += tests/various
 | 
				
			||||||
 | 
					ifeq ($(ENABLE_VERIFIC),1)
 | 
				
			||||||
 | 
					ifneq ($(YOSYS_NOVERIFIC),1)
 | 
				
			||||||
 | 
					MK_TEST_DIRS += tests/verific
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					MK_TEST_DIRS += tests/verilog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Tests that don't generate .mk
 | 
				
			||||||
 | 
					SH_TEST_DIRS =
 | 
				
			||||||
 | 
					SH_TEST_DIRS += tests/simple
 | 
				
			||||||
 | 
					SH_TEST_DIRS += tests/simple_abc9
 | 
				
			||||||
 | 
					SH_TEST_DIRS += tests/hana
 | 
				
			||||||
 | 
					SH_TEST_DIRS += tests/asicworld
 | 
				
			||||||
 | 
					# SH_TEST_DIRS += tests/realmath
 | 
				
			||||||
 | 
					SH_TEST_DIRS += tests/share
 | 
				
			||||||
 | 
					SH_TEST_DIRS += tests/opt_share
 | 
				
			||||||
 | 
					# SH_TEST_DIRS += tests/fsm
 | 
				
			||||||
 | 
					SH_TEST_DIRS += tests/memlib
 | 
				
			||||||
 | 
					# SH_TEST_DIRS += tests/bram
 | 
				
			||||||
 | 
					SH_TEST_DIRS += tests/svinterfaces
 | 
				
			||||||
 | 
					SH_TEST_DIRS += tests/xprop
 | 
				
			||||||
 | 
					SH_TEST_DIRS += tests/select
 | 
				
			||||||
 | 
					SH_TEST_DIRS += tests/proc
 | 
				
			||||||
 | 
					SH_TEST_DIRS += tests/blif
 | 
				
			||||||
 | 
					SH_TEST_DIRS += tests/arch
 | 
				
			||||||
 | 
					SH_TEST_DIRS += tests/rpc
 | 
				
			||||||
 | 
					SH_TEST_DIRS += tests/memfile
 | 
				
			||||||
 | 
					SH_TEST_DIRS += tests/fmt
 | 
				
			||||||
 | 
					# SH_TEST_DIRS += tests/cxxrtl
 | 
				
			||||||
 | 
					ifeq ($(ENABLE_FUNCTIONAL_TESTS),1)
 | 
				
			||||||
 | 
					SH_TEST_DIRS += tests/functional
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test: $(TARGETS) $(EXTRA_TARGETS)
 | 
					# Tests that don't generate .mk and need special args
 | 
				
			||||||
ifeq ($(ENABLE_VERIFIC),1)
 | 
					SH_ABC_TEST_DIRS =
 | 
				
			||||||
ifeq ($(YOSYS_NOVERIFIC),1)
 | 
					SH_ABC_TEST_DIRS += tests/memories
 | 
				
			||||||
	@echo
 | 
					SH_ABC_TEST_DIRS += tests/aiger
 | 
				
			||||||
	@echo "Running tests without verific support due to YOSYS_NOVERIFIC=1"
 | 
					
 | 
				
			||||||
	@echo
 | 
					# seed-tests/ is a dummy string, not a directory
 | 
				
			||||||
else
 | 
					.PHONY: seed-tests
 | 
				
			||||||
	+cd tests/verific && bash run-test.sh $(SEEDOPT)
 | 
					seed-tests: $(SH_TEST_DIRS:%=seed-tests/%)
 | 
				
			||||||
endif
 | 
					.PHONY: seed-tests/%
 | 
				
			||||||
endif
 | 
					seed-tests/%: %/run-test.sh $(TARGETS) $(EXTRA_TARGETS)
 | 
				
			||||||
	+cd tests/simple && bash run-test.sh $(SEEDOPT)
 | 
						+cd $* && bash run-test.sh $(SEEDOPT)
 | 
				
			||||||
	+cd tests/simple_abc9 && bash run-test.sh $(SEEDOPT)
 | 
						+@echo "...passed tests in $*"
 | 
				
			||||||
	+cd tests/hana && bash run-test.sh $(SEEDOPT)
 | 
					
 | 
				
			||||||
	+cd tests/asicworld && bash run-test.sh $(SEEDOPT)
 | 
					# abcopt-tests/ is a dummy string, not a directory
 | 
				
			||||||
	# +cd tests/realmath && bash run-test.sh $(SEEDOPT)
 | 
					.PHONY: abcopt-tests
 | 
				
			||||||
	+cd tests/share && bash run-test.sh $(SEEDOPT)
 | 
					abcopt-tests: $(SH_ABC_TEST_DIRS:%=abcopt-tests/%)
 | 
				
			||||||
	+cd tests/opt_share && bash run-test.sh $(SEEDOPT)
 | 
					abcopt-tests/%: %/run-test.sh $(TARGETS) $(EXTRA_TARGETS)
 | 
				
			||||||
	# +cd tests/fsm && bash run-test.sh $(SEEDOPT)
 | 
						+cd $* && bash run-test.sh $(ABCOPT) $(SEEDOPT)
 | 
				
			||||||
	+cd tests/techmap && bash run-test.sh
 | 
						+@echo "...passed tests in $*"
 | 
				
			||||||
	+cd tests/memories && bash run-test.sh $(ABCOPT) $(SEEDOPT)
 | 
					
 | 
				
			||||||
	+cd tests/memlib && bash run-test.sh $(SEEDOPT)
 | 
					# makefile-tests/ is a dummy string, not a directory
 | 
				
			||||||
	# +cd tests/bram && bash run-test.sh $(SEEDOPT)
 | 
					.PHONY: makefile-tests
 | 
				
			||||||
	+cd tests/various && bash run-test.sh
 | 
					makefile-tests: $(MK_TEST_DIRS:%=makefile-tests/%)
 | 
				
			||||||
	+cd tests/select && bash run-test.sh
 | 
					# this target actually emits .mk files
 | 
				
			||||||
	+cd tests/sat && bash run-test.sh
 | 
					%.mk:
 | 
				
			||||||
	+cd tests/sim && bash run-test.sh
 | 
						+cd $(dir $*) && bash run-test.sh
 | 
				
			||||||
	+cd tests/svinterfaces && bash run-test.sh $(SEEDOPT)
 | 
					# this one spawns submake on each
 | 
				
			||||||
	+cd tests/svtypes && bash run-test.sh $(SEEDOPT)
 | 
					makefile-tests/%: %/run-test.mk $(TARGETS) $(EXTRA_TARGETS)
 | 
				
			||||||
	+cd tests/proc && bash run-test.sh
 | 
						$(MAKE) -C $* -f run-test.mk
 | 
				
			||||||
	+cd tests/blif && bash run-test.sh
 | 
						+@echo "...passed tests in $*"
 | 
				
			||||||
	+cd tests/opt && bash run-test.sh
 | 
					
 | 
				
			||||||
	# +cd tests/aiger && bash run-test.sh $(ABCOPT)
 | 
					test: makefile-tests abcopt-tests seed-tests
 | 
				
			||||||
	# +cd tests/arch && bash run-test.sh
 | 
					 | 
				
			||||||
	# +cd tests/arch/ice40 && bash run-test.sh $(SEEDOPT)
 | 
					 | 
				
			||||||
	# +cd tests/arch/xilinx && bash run-test.sh $(SEEDOPT)
 | 
					 | 
				
			||||||
	# +cd tests/arch/ecp5 && bash run-test.sh $(SEEDOPT)
 | 
					 | 
				
			||||||
	# +cd tests/arch/machxo2 && bash run-test.sh $(SEEDOPT)
 | 
					 | 
				
			||||||
	# +cd tests/arch/efinix && bash run-test.sh $(SEEDOPT)
 | 
					 | 
				
			||||||
	# +cd tests/arch/anlogic && bash run-test.sh $(SEEDOPT)
 | 
					 | 
				
			||||||
	# +cd tests/arch/gowin && bash run-test.sh $(SEEDOPT)
 | 
					 | 
				
			||||||
	# +cd tests/arch/intel_alm && bash run-test.sh $(SEEDOPT)
 | 
					 | 
				
			||||||
	# +cd tests/arch/nanoxplore && bash run-test.sh $(SEEDOPT)
 | 
					 | 
				
			||||||
	# +cd tests/arch/nexus && bash run-test.sh $(SEEDOPT)
 | 
					 | 
				
			||||||
	# +cd tests/arch/quicklogic/pp3 && bash run-test.sh $(SEEDOPT)
 | 
					 | 
				
			||||||
	# +cd tests/arch/quicklogic/qlf_k6n10f && bash run-test.sh $(SEEDOPT)
 | 
					 | 
				
			||||||
	# +cd tests/arch/gatemate && bash run-test.sh $(SEEDOPT)
 | 
					 | 
				
			||||||
	# +cd tests/arch/microchip && bash run-test.sh $(SEEDOPT)
 | 
					 | 
				
			||||||
	+cd tests/rpc && bash run-test.sh
 | 
					 | 
				
			||||||
	+cd tests/memfile && bash run-test.sh
 | 
					 | 
				
			||||||
	+cd tests/verilog && bash run-test.sh
 | 
					 | 
				
			||||||
	+cd tests/xprop && bash run-test.sh $(SEEDOPT)
 | 
					 | 
				
			||||||
	+cd tests/fmt && bash run-test.sh
 | 
					 | 
				
			||||||
	# +cd tests/cxxrtl && bash run-test.sh
 | 
					 | 
				
			||||||
	+cd tests/liberty && bash run-test.sh
 | 
					 | 
				
			||||||
ifeq ($(ENABLE_FUNCTIONAL_TESTS),1)
 | 
					 | 
				
			||||||
	+cd tests/functional && bash run-test.sh
 | 
					 | 
				
			||||||
endif
 | 
					 | 
				
			||||||
	@echo ""
 | 
						@echo ""
 | 
				
			||||||
	@echo "  Passed \"make test\"."
 | 
						@echo "  Passed \"make test\"."
 | 
				
			||||||
 | 
					ifeq ($(ENABLE_VERIFIC),1)
 | 
				
			||||||
 | 
					ifeq ($(YOSYS_NOVERIFIC),1)
 | 
				
			||||||
 | 
						@echo "  Ran tests without verific support due to YOSYS_NOVERIFIC=1."
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
	@echo ""
 | 
						@echo ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VALGRIND ?= valgrind --error-exitcode=1 --leak-check=full --show-reachable=yes --errors-for-leak-kinds=all
 | 
					VALGRIND ?= valgrind --error-exitcode=1 --leak-check=full --show-reachable=yes --errors-for-leak-kinds=all
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,7 +47,7 @@ struct Scheduler {
 | 
				
			||||||
	struct Vertex {
 | 
						struct Vertex {
 | 
				
			||||||
		T *data;
 | 
							T *data;
 | 
				
			||||||
		Vertex *prev, *next;
 | 
							Vertex *prev, *next;
 | 
				
			||||||
		pool<Vertex*, hash_ptr_ops> preds, succs;
 | 
							pool<Vertex*> preds, succs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Vertex() : data(NULL), prev(this), next(this) {}
 | 
							Vertex() : data(NULL), prev(this), next(this) {}
 | 
				
			||||||
		Vertex(T *data) : data(data), prev(NULL), next(NULL) {}
 | 
							Vertex(T *data) : data(data), prev(NULL), next(NULL) {}
 | 
				
			||||||
| 
						 | 
					@ -300,10 +300,10 @@ struct FlowGraph {
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::vector<Node*> nodes;
 | 
						std::vector<Node*> nodes;
 | 
				
			||||||
	dict<const RTLIL::Wire*, pool<Node*, hash_ptr_ops>> wire_comb_defs, wire_sync_defs, wire_uses;
 | 
						dict<const RTLIL::Wire*, pool<Node*>> wire_comb_defs, wire_sync_defs, wire_uses;
 | 
				
			||||||
	dict<Node*, pool<const RTLIL::Wire*>, hash_ptr_ops> node_comb_defs, node_sync_defs, node_uses;
 | 
						dict<Node*, pool<const RTLIL::Wire*>> node_comb_defs, node_sync_defs, node_uses;
 | 
				
			||||||
	dict<const RTLIL::Wire*, bool> wire_def_inlinable;
 | 
						dict<const RTLIL::Wire*, bool> wire_def_inlinable;
 | 
				
			||||||
	dict<const RTLIL::Wire*, dict<Node*, bool, hash_ptr_ops>> wire_use_inlinable;
 | 
						dict<const RTLIL::Wire*, dict<Node*, bool>> wire_use_inlinable;
 | 
				
			||||||
	dict<RTLIL::SigBit, bool> bit_has_state;
 | 
						dict<RTLIL::SigBit, bool> bit_has_state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	~FlowGraph()
 | 
						~FlowGraph()
 | 
				
			||||||
| 
						 | 
					@ -365,7 +365,7 @@ struct FlowGraph {
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool is_inlinable(const RTLIL::Wire *wire, const pool<Node*, hash_ptr_ops> &nodes) const
 | 
						bool is_inlinable(const RTLIL::Wire *wire, const pool<Node*> &nodes) const
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// Can the wire be inlined, knowing that the given nodes are reachable?
 | 
							// Can the wire be inlined, knowing that the given nodes are reachable?
 | 
				
			||||||
		if (nodes.size() != 1)
 | 
							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
 | 
								// without feedback arcs can generally be evaluated in a single pass, i.e. it always requires only
 | 
				
			||||||
			// a single delta cycle.
 | 
								// a single delta cycle.
 | 
				
			||||||
			Scheduler<FlowGraph::Node> scheduler;
 | 
								Scheduler<FlowGraph::Node> scheduler;
 | 
				
			||||||
			dict<FlowGraph::Node*, Scheduler<FlowGraph::Node>::Vertex*, hash_ptr_ops> node_vertex_map;
 | 
								dict<FlowGraph::Node*, Scheduler<FlowGraph::Node>::Vertex*> node_vertex_map;
 | 
				
			||||||
			for (auto node : flow.nodes)
 | 
								for (auto node : flow.nodes)
 | 
				
			||||||
				node_vertex_map[node] = scheduler.add(node);
 | 
									node_vertex_map[node] = scheduler.add(node);
 | 
				
			||||||
			for (auto node_comb_def : flow.node_comb_defs) {
 | 
								for (auto node_comb_def : flow.node_comb_defs) {
 | 
				
			||||||
| 
						 | 
					@ -3095,7 +3095,7 @@ struct CxxrtlWorker {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Find out whether the order includes any feedback arcs.
 | 
								// Find out whether the order includes any feedback arcs.
 | 
				
			||||||
			std::vector<FlowGraph::Node*> node_order;
 | 
								std::vector<FlowGraph::Node*> node_order;
 | 
				
			||||||
			pool<FlowGraph::Node*, hash_ptr_ops> evaluated_nodes;
 | 
								pool<FlowGraph::Node*> evaluated_nodes;
 | 
				
			||||||
			pool<const RTLIL::Wire*> feedback_wires;
 | 
								pool<const RTLIL::Wire*> feedback_wires;
 | 
				
			||||||
			for (auto vertex : scheduler.schedule()) {
 | 
								for (auto vertex : scheduler.schedule()) {
 | 
				
			||||||
				auto node = vertex->data;
 | 
									auto node = vertex->data;
 | 
				
			||||||
| 
						 | 
					@ -3139,7 +3139,7 @@ struct CxxrtlWorker {
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Discover nodes reachable from primary outputs (i.e. members) and collect reachable wire users.
 | 
								// Discover nodes reachable from primary outputs (i.e. members) and collect reachable wire users.
 | 
				
			||||||
			pool<FlowGraph::Node*, hash_ptr_ops> worklist;
 | 
								pool<FlowGraph::Node*> worklist;
 | 
				
			||||||
			for (auto node : flow.nodes) {
 | 
								for (auto node : flow.nodes) {
 | 
				
			||||||
				if (node->type == FlowGraph::Node::Type::CELL_EVAL && !is_internal_cell(node->cell->type))
 | 
									if (node->type == FlowGraph::Node::Type::CELL_EVAL && !is_internal_cell(node->cell->type))
 | 
				
			||||||
					worklist.insert(node); // node evaluates a submodule
 | 
										worklist.insert(node); // node evaluates a submodule
 | 
				
			||||||
| 
						 | 
					@ -3159,8 +3159,8 @@ struct CxxrtlWorker {
 | 
				
			||||||
							worklist.insert(node); // node drives public wires
 | 
												worklist.insert(node); // node drives public wires
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			dict<const RTLIL::Wire*, pool<FlowGraph::Node*, hash_ptr_ops>> live_wires;
 | 
								dict<const RTLIL::Wire*, pool<FlowGraph::Node*>> live_wires;
 | 
				
			||||||
			pool<FlowGraph::Node*, hash_ptr_ops> live_nodes;
 | 
								pool<FlowGraph::Node*> live_nodes;
 | 
				
			||||||
			while (!worklist.empty()) {
 | 
								while (!worklist.empty()) {
 | 
				
			||||||
				auto node = worklist.pop();
 | 
									auto node = worklist.pop();
 | 
				
			||||||
				live_nodes.insert(node);
 | 
									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)
 | 
									// Discover nodes reachable from primary outputs (i.e. outlines) up until primary inputs (i.e. members)
 | 
				
			||||||
				// and collect reachable wire users.
 | 
									// and collect reachable wire users.
 | 
				
			||||||
				pool<FlowGraph::Node*, hash_ptr_ops> worklist;
 | 
									pool<FlowGraph::Node*> worklist;
 | 
				
			||||||
				for (auto node : flow.nodes) {
 | 
									for (auto node : flow.nodes) {
 | 
				
			||||||
					if (flow.node_comb_defs.count(node))
 | 
										if (flow.node_comb_defs.count(node))
 | 
				
			||||||
						for (auto wire : flow.node_comb_defs[node])
 | 
											for (auto wire : flow.node_comb_defs[node])
 | 
				
			||||||
							if (debug_wire_types[wire].is_outline())
 | 
												if (debug_wire_types[wire].is_outline())
 | 
				
			||||||
								worklist.insert(node); // node drives outline
 | 
													worklist.insert(node); // node drives outline
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				dict<const RTLIL::Wire*, pool<FlowGraph::Node*, hash_ptr_ops>> debug_live_wires;
 | 
									dict<const RTLIL::Wire*, pool<FlowGraph::Node*>> debug_live_wires;
 | 
				
			||||||
				pool<FlowGraph::Node*, hash_ptr_ops> debug_live_nodes;
 | 
									pool<FlowGraph::Node*> debug_live_nodes;
 | 
				
			||||||
				while (!worklist.empty()) {
 | 
									while (!worklist.empty()) {
 | 
				
			||||||
					auto node = worklist.pop();
 | 
										auto node = worklist.pop();
 | 
				
			||||||
					debug_live_nodes.insert(node);
 | 
										debug_live_nodes.insert(node);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										155
									
								
								docs/source/yosys_internals/hashing.rst
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								docs/source/yosys_internals/hashing.rst
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,155 @@
 | 
				
			||||||
 | 
					Hashing and associative data structures in Yosys
 | 
				
			||||||
 | 
					------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Container classes based on hashing
 | 
				
			||||||
 | 
					~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Yosys uses ``dict<K, T>`` and ``pool<T>`` as main container classes.
 | 
				
			||||||
 | 
					``dict<K, T>`` is essentially a replacement for ``std::unordered_map<K, T>``
 | 
				
			||||||
 | 
					and ``pool<T>`` is a replacement for ``std::unordered_set<T>``.
 | 
				
			||||||
 | 
					The main characteristics are:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* ``dict<K, T>`` and ``pool<T>`` 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<K, T>`` or ``pool<T>`` are invalidated by
 | 
				
			||||||
 | 
					   insert and remove operations (similar to ``std::vector<T>`` 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<K, T>`` and ``pool<T>`` will have the same order of iteration across
 | 
				
			||||||
 | 
					   all compilers, standard libraries and architectures.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In addition to ``dict<K, T>`` and ``pool<T>`` there is also an ``idict<K>`` that
 | 
				
			||||||
 | 
					creates a bijective map from ``K`` to the integers. For example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   idict<string, 42> 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<K>`` implements a merge-find set data structure (aka. disjoint-set
 | 
				
			||||||
 | 
					or union-find) over the type ``K`` ("mfp" = merge-find-promote).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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<T>(const T& obj)``, corresponding to ``hash_top_ops<T>::hash(obj)``,
 | 
				
			||||||
 | 
					the default implementation of which is ``hash_ops<T>::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<T>`` is the star of the show. By default it pulls the ``Hasher h``
 | 
				
			||||||
 | 
					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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					``hash_ops<T>`` 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<Wire*>``
 | 
				
			||||||
 | 
					and others in ``kernel/hashlib.h`` that actually dereference the pointers and
 | 
				
			||||||
 | 
					call ``hash_into`` on the instances pointed to.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					``hash_ops<T>`` is also specialized for simple compound types like
 | 
				
			||||||
 | 
					``std::pair<U>`` by calling hash_into in sequence on its members. For flexible
 | 
				
			||||||
 | 
					size containers like ``std::vector<U>`` 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
 | 
				
			||||||
 | 
					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<RTLIL::SigBit>`` 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 both interfaces
 | 
				
			||||||
 | 
					based on the existance and value of `YS_HASHING_VERSION`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: cpp
 | 
				
			||||||
 | 
					   :caption: Example hash compatibility wrapper
 | 
				
			||||||
 | 
					   :name: hash_plugin_compat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   #ifndef YS_HASHING_VERSION
 | 
				
			||||||
 | 
					   unsigned int T::hash() const {
 | 
				
			||||||
 | 
					      return mkhash(a, b);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   #elif YS_HASHING_VERSION == 1
 | 
				
			||||||
 | 
					   Hasher T::hash_into(Hasher h) const {
 | 
				
			||||||
 | 
					      h.eat(a);
 | 
				
			||||||
 | 
					      h.eat(b);
 | 
				
			||||||
 | 
					      return h;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   #else
 | 
				
			||||||
 | 
					   #error "Unsupported hashing interface"
 | 
				
			||||||
 | 
					   #endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Feel free to contact Yosys maintainers with related issues.
 | 
				
			||||||
| 
						 | 
					@ -39,3 +39,4 @@ as reference to implement a similar system in any language.
 | 
				
			||||||
   extending_yosys/index
 | 
					   extending_yosys/index
 | 
				
			||||||
   techmap
 | 
					   techmap
 | 
				
			||||||
   verilog
 | 
					   verilog
 | 
				
			||||||
 | 
					   hashing
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -90,7 +90,7 @@ struct ScopeinfoExamplePass : public Pass {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				// Shuffle wires so this example produces more interesting outputs
 | 
									// Shuffle wires so this example produces more interesting outputs
 | 
				
			||||||
				std::sort(wires.begin(), wires.end(), [](Wire *a, Wire *b) {
 | 
									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);
 | 
									ModuleHdlnameIndex index(module);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,15 +14,15 @@
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        # TODO: don't override src when ./abc is empty
 | 
					        # TODO: don't override src when ./abc is empty
 | 
				
			||||||
        # which happens when the command used is `nix build` and not `nix build ?submodules=1`
 | 
					        # 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 {
 | 
					        yosys = pkgs.clangStdenv.mkDerivation {
 | 
				
			||||||
          name = "yosys";
 | 
					          name = "yosys";
 | 
				
			||||||
          src = ./. ;
 | 
					          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 ];
 | 
					          checkInputs = with pkgs; [ gtest ];
 | 
				
			||||||
          propagatedBuildInputs = [ abc-verifier ];
 | 
					          propagatedBuildInputs = [ abc-verifier ];
 | 
				
			||||||
          preConfigure = "make config-clang";
 | 
					          preConfigure = "make config-clang";
 | 
				
			||||||
          checkTarget = "test";
 | 
					          checkTarget = "unit-test";
 | 
				
			||||||
          installPhase = ''
 | 
					          installPhase = ''
 | 
				
			||||||
            make install PREFIX=$out ABCEXTERNAL=yosys-abc
 | 
					            make install PREFIX=$out ABCEXTERNAL=yosys-abc
 | 
				
			||||||
            ln -s ${abc-verifier}/bin/abc $out/bin/yosys-abc
 | 
					            ln -s ${abc-verifier}/bin/abc $out/bin/yosys-abc
 | 
				
			||||||
| 
						 | 
					@ -41,7 +41,7 @@
 | 
				
			||||||
        packages.default = yosys;
 | 
					        packages.default = yosys;
 | 
				
			||||||
        defaultPackage = yosys;
 | 
					        defaultPackage = yosys;
 | 
				
			||||||
        devShell = pkgs.mkShell {
 | 
					        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 ];
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -177,7 +177,7 @@ namespace AST
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// for dict<> and pool<>
 | 
							// for dict<> and pool<>
 | 
				
			||||||
		unsigned int hashidx_;
 | 
							unsigned int hashidx_;
 | 
				
			||||||
		unsigned int hash() const { return hashidx_; }
 | 
							Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// this nodes type
 | 
							// this nodes type
 | 
				
			||||||
		AstNodeType type;
 | 
							AstNodeType type;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -637,7 +637,7 @@ RTLIL::SigSpec VerificImporter::operatorInportCase(Instance *inst, const char *p
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RTLIL::SigSpec VerificImporter::operatorOutput(Instance *inst, const pool<Net*, hash_ptr_ops> *any_all_nets)
 | 
					RTLIL::SigSpec VerificImporter::operatorOutput(Instance *inst, const pool<Net*> *any_all_nets)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	RTLIL::SigSpec sig;
 | 
						RTLIL::SigSpec sig;
 | 
				
			||||||
	RTLIL::Wire *dummy_wire = NULL;
 | 
						RTLIL::Wire *dummy_wire = NULL;
 | 
				
			||||||
| 
						 | 
					@ -1644,9 +1644,9 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	module->fixup_ports();
 | 
						module->fixup_ports();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dict<Net*, char, hash_ptr_ops> init_nets;
 | 
						dict<Net*, char> init_nets;
 | 
				
			||||||
	pool<Net*, hash_ptr_ops> anyconst_nets, anyseq_nets;
 | 
						pool<Net*> anyconst_nets, anyseq_nets;
 | 
				
			||||||
	pool<Net*, hash_ptr_ops> allconst_nets, allseq_nets;
 | 
						pool<Net*> allconst_nets, allseq_nets;
 | 
				
			||||||
	any_all_nets.clear();
 | 
						any_all_nets.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	FOREACH_NET_OF_NETLIST(nl, mi, net)
 | 
						FOREACH_NET_OF_NETLIST(nl, mi, net)
 | 
				
			||||||
| 
						 | 
					@ -1909,10 +1909,10 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
 | 
				
			||||||
		module->connect(net_map_at(net), module->Anyseq(new_verific_id(net)));
 | 
							module->connect(net_map_at(net), module->Anyseq(new_verific_id(net)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef VERIFIC_SYSTEMVERILOG_SUPPORT
 | 
					#ifdef VERIFIC_SYSTEMVERILOG_SUPPORT
 | 
				
			||||||
	pool<Instance*, hash_ptr_ops> sva_asserts;
 | 
						pool<Instance*> sva_asserts;
 | 
				
			||||||
	pool<Instance*, hash_ptr_ops> sva_assumes;
 | 
						pool<Instance*> sva_assumes;
 | 
				
			||||||
	pool<Instance*, hash_ptr_ops> sva_covers;
 | 
						pool<Instance*> sva_covers;
 | 
				
			||||||
	pool<Instance*, hash_ptr_ops> sva_triggers;
 | 
						pool<Instance*> sva_triggers;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pool<RTLIL::Cell*> past_ffs;
 | 
						pool<RTLIL::Cell*> past_ffs;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -72,7 +72,7 @@ struct VerificImporter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::map<Verific::Net*, RTLIL::SigBit> net_map;
 | 
						std::map<Verific::Net*, RTLIL::SigBit> net_map;
 | 
				
			||||||
	std::map<Verific::Net*, Verific::Net*> sva_posedge_map;
 | 
						std::map<Verific::Net*, Verific::Net*> sva_posedge_map;
 | 
				
			||||||
	pool<Verific::Net*, hash_ptr_ops> any_all_nets;
 | 
						pool<Verific::Net*> any_all_nets;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool mode_gates, mode_keep, mode_nosva, mode_names, mode_verific;
 | 
						bool mode_gates, mode_keep, mode_nosva, mode_names, mode_verific;
 | 
				
			||||||
	bool mode_autocover, mode_fullinit;
 | 
						bool mode_autocover, mode_fullinit;
 | 
				
			||||||
| 
						 | 
					@ -91,7 +91,7 @@ struct VerificImporter
 | 
				
			||||||
	RTLIL::SigSpec operatorInput2(Verific::Instance *inst);
 | 
						RTLIL::SigSpec operatorInput2(Verific::Instance *inst);
 | 
				
			||||||
	RTLIL::SigSpec operatorInport(Verific::Instance *inst, const char *portname);
 | 
						RTLIL::SigSpec operatorInport(Verific::Instance *inst, const char *portname);
 | 
				
			||||||
	RTLIL::SigSpec operatorInportCase(Verific::Instance *inst, const char *portname);
 | 
						RTLIL::SigSpec operatorInportCase(Verific::Instance *inst, const char *portname);
 | 
				
			||||||
	RTLIL::SigSpec operatorOutput(Verific::Instance *inst, const pool<Verific::Net*, hash_ptr_ops> *any_all_nets = nullptr);
 | 
						RTLIL::SigSpec operatorOutput(Verific::Instance *inst, const pool<Verific::Net*> *any_all_nets = nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool import_netlist_instance_gates(Verific::Instance *inst, RTLIL::IdString inst_name);
 | 
						bool import_netlist_instance_gates(Verific::Instance *inst, RTLIL::IdString inst_name);
 | 
				
			||||||
	bool import_netlist_instance_cells(Verific::Instance *inst, RTLIL::IdString inst_name);
 | 
						bool import_netlist_instance_cells(Verific::Instance *inst, RTLIL::IdString inst_name);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1051,7 +1051,7 @@ struct VerificSvaImporter
 | 
				
			||||||
				msg.c_str(), inst->View()->Owner()->Name(), inst->Name()), inst->Linefile());
 | 
									msg.c_str(), inst->View()->Owner()->Name(), inst->Name()), inst->Linefile());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dict<Net*, bool, hash_ptr_ops> check_expression_cache;
 | 
						dict<Net*, bool> check_expression_cache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool check_expression(Net *net, bool raise_error = false)
 | 
						bool check_expression(Net *net, bool raise_error = false)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,57 +37,15 @@ And then executed using the following command:
 | 
				
			||||||
Yosys Data Structures
 | 
					Yosys Data Structures
 | 
				
			||||||
---------------------
 | 
					---------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Here is a short list of data structures that you should make yourself familiar
 | 
					  1. Container classes based on hashing
 | 
				
			||||||
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. Yosys Container Classes
 | 
					Yosys heavily relies on custom container data structures such as dict or pool
 | 
				
			||||||
 | 
					defined in kernel/hashlib.h.
 | 
				
			||||||
 | 
					dict<K, T> is essentially a replacement for std::unordered_map<K, T>
 | 
				
			||||||
 | 
					and pool<T> is a replacement for std::unordered_set<T>. Please refer to
 | 
				
			||||||
 | 
					docs/source/yosys_internals/hashing.rst for more information on those.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Yosys uses dict<K, T> and pool<T> as main container classes. dict<K, T> is
 | 
					Otherwise, Yosys makes use of the following:
 | 
				
			||||||
essentially a replacement for std::unordered_map<K, T> and pool<T> is a
 | 
					 | 
				
			||||||
replacement for std::unordered_set<T>. The main characteristics are:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	- dict<K, T> and pool<T> are about 2x faster than the std containers
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	- references to elements in a dict<K, T> or pool<T> are invalidated by
 | 
					 | 
				
			||||||
	  insert and remove operations (similar to std::vector<T> 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<K, T> and pool<T> will have the same order of iteration across
 | 
					 | 
				
			||||||
	  all compilers, standard libraries and architectures.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
In addition to dict<K, T> and pool<T> there is also an idict<K> that
 | 
					 | 
				
			||||||
creates a bijective map from K to the integers. For example:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	idict<string, 42> 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<K> implements a merge-find set data structure (aka. disjoint-set or
 | 
					 | 
				
			||||||
union-find) over the type K ("mfp" = merge-find-promote).
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  2. Standard STL data types
 | 
					  2. Standard STL data types
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,7 +30,7 @@ struct BitPatternPool
 | 
				
			||||||
	int width;
 | 
						int width;
 | 
				
			||||||
	struct bits_t {
 | 
						struct bits_t {
 | 
				
			||||||
		std::vector<RTLIL::State> bitdata;
 | 
							std::vector<RTLIL::State> bitdata;
 | 
				
			||||||
		mutable unsigned int cached_hash;
 | 
							mutable Hasher::hash_t cached_hash;
 | 
				
			||||||
		bits_t(int width = 0) : bitdata(width), cached_hash(0) { }
 | 
							bits_t(int width = 0) : bitdata(width), cached_hash(0) { }
 | 
				
			||||||
		RTLIL::State &operator[](int index) {
 | 
							RTLIL::State &operator[](int index) {
 | 
				
			||||||
			return bitdata[index];
 | 
								return bitdata[index];
 | 
				
			||||||
| 
						 | 
					@ -39,14 +39,15 @@ struct BitPatternPool
 | 
				
			||||||
			return bitdata[index];
 | 
								return bitdata[index];
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		bool operator==(const bits_t &other) const {
 | 
							bool operator==(const bits_t &other) const {
 | 
				
			||||||
			if (hash() != other.hash())
 | 
								if (run_hash(*this) != run_hash(other))
 | 
				
			||||||
				return false;
 | 
									return false;
 | 
				
			||||||
			return bitdata == other.bitdata;
 | 
								return bitdata == other.bitdata;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		unsigned int hash() const {
 | 
							Hasher hash_into(Hasher h) const {
 | 
				
			||||||
			if (!cached_hash)
 | 
								if (!cached_hash)
 | 
				
			||||||
				cached_hash = hash_ops<std::vector<RTLIL::State>>::hash(bitdata);
 | 
									cached_hash = run_hash(bitdata);
 | 
				
			||||||
			return cached_hash;
 | 
								h.eat(cached_hash);
 | 
				
			||||||
 | 
								return h;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	pool<bits_t> database;
 | 
						pool<bits_t> database;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,13 +39,13 @@ bool AigNode::operator==(const AigNode &other) const
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
unsigned int AigNode::hash() const
 | 
					Hasher AigNode::hash_into(Hasher h) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int h = mkhash_init;
 | 
						h.eat(portname);
 | 
				
			||||||
	h = mkhash(portname.hash(), portbit);
 | 
						h.eat(portbit);
 | 
				
			||||||
	h = mkhash(h, inverter);
 | 
						h.eat(inverter);
 | 
				
			||||||
	h = mkhash(h, left_parent);
 | 
						h.eat(left_parent);
 | 
				
			||||||
	h = mkhash(h, right_parent);
 | 
						h.eat(right_parent);
 | 
				
			||||||
	return h;
 | 
						return h;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -54,9 +54,10 @@ bool Aig::operator==(const Aig &other) const
 | 
				
			||||||
	return name == other.name;
 | 
						return name == other.name;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
unsigned int Aig::hash() const
 | 
					Hasher Aig::hash_into(Hasher h) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return hash_ops<std::string>::hash(name);
 | 
						h.eat(name);
 | 
				
			||||||
 | 
						return h;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct AigMaker
 | 
					struct AigMaker
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,7 +34,7 @@ struct AigNode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	AigNode();
 | 
						AigNode();
 | 
				
			||||||
	bool operator==(const AigNode &other) const;
 | 
						bool operator==(const AigNode &other) const;
 | 
				
			||||||
	unsigned int hash() const;
 | 
						Hasher hash_into(Hasher h) const;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Aig
 | 
					struct Aig
 | 
				
			||||||
| 
						 | 
					@ -44,7 +44,7 @@ struct Aig
 | 
				
			||||||
	Aig(Cell *cell);
 | 
						Aig(Cell *cell);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool operator==(const Aig &other) const;
 | 
						bool operator==(const Aig &other) const;
 | 
				
			||||||
	unsigned int hash() const;
 | 
						Hasher hash_into(Hasher h) const;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
YOSYS_NAMESPACE_END
 | 
					YOSYS_NAMESPACE_END
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,6 +18,7 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "kernel/yosys.h"
 | 
					#include "kernel/yosys.h"
 | 
				
			||||||
 | 
					#include "kernel/hashlib.h"
 | 
				
			||||||
#include "libs/sha1/sha1.h"
 | 
					#include "libs/sha1/sha1.h"
 | 
				
			||||||
#include "libs/cxxopts/include/cxxopts.hpp"
 | 
					#include "libs/cxxopts/include/cxxopts.hpp"
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
| 
						 | 
					@ -282,6 +283,8 @@ int main(int argc, char **argv)
 | 
				
			||||||
		("M,randomize-pointers", "will slightly randomize allocated pointer addresses. for debugging")
 | 
							("M,randomize-pointers", "will slightly randomize allocated pointer addresses. for debugging")
 | 
				
			||||||
		("autoidx", "start counting autoidx up from <seed>, similar effect to --hash-seed",
 | 
							("autoidx", "start counting autoidx up from <seed>, similar effect to --hash-seed",
 | 
				
			||||||
			cxxopts::value<uint64_t>(), "<idx>")
 | 
								cxxopts::value<uint64_t>(), "<idx>")
 | 
				
			||||||
 | 
							("hash-seed", "mix up hashing values with <seed>, for extreme optimization and testing",
 | 
				
			||||||
 | 
								cxxopts::value<uint64_t>(), "<seed>")
 | 
				
			||||||
		("A,abort", "will call abort() at the end of the script. for debugging")
 | 
							("A,abort", "will call abort() at the end of the script. for debugging")
 | 
				
			||||||
		("x,experimental", "do not print warnings for the experimental <feature>",
 | 
							("x,experimental", "do not print warnings for the experimental <feature>",
 | 
				
			||||||
			cxxopts::value<std::vector<std::string>>(), "<feature>")
 | 
								cxxopts::value<std::vector<std::string>>(), "<feature>")
 | 
				
			||||||
| 
						 | 
					@ -437,6 +440,10 @@ int main(int argc, char **argv)
 | 
				
			||||||
			int idx = result["autoidx"].as<uint64_t>();
 | 
								int idx = result["autoidx"].as<uint64_t>();
 | 
				
			||||||
			autoidx = idx;
 | 
								autoidx = idx;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if (result.count("hash-seed")) {
 | 
				
			||||||
 | 
								int seed = result["hash-seed"].as<uint64_t>();
 | 
				
			||||||
 | 
								Hasher::set_fudge((Hasher::hash_t)seed);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (log_errfile == NULL) {
 | 
							if (log_errfile == NULL) {
 | 
				
			||||||
			log_files.push_back(stdout);
 | 
								log_files.push_back(stdout);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -74,10 +74,8 @@ struct DriveBitWire
 | 
				
			||||||
		return offset < other.offset;
 | 
							return offset < other.offset;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int hash() const
 | 
						Hasher hash_into(Hasher h) const;
 | 
				
			||||||
	{
 | 
					
 | 
				
			||||||
		return mkhash_add(wire->name.hash(), offset);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	operator SigBit() const
 | 
						operator SigBit() const
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
| 
						 | 
					@ -107,10 +105,8 @@ struct DriveBitPort
 | 
				
			||||||
		return offset < other.offset;
 | 
							return offset < other.offset;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int hash() const
 | 
						Hasher hash_into(Hasher h) const;
 | 
				
			||||||
	{
 | 
					
 | 
				
			||||||
		return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -133,10 +129,7 @@ struct DriveBitMarker
 | 
				
			||||||
		return offset < other.offset;
 | 
							return offset < other.offset;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int hash() const
 | 
						Hasher hash_into(Hasher h) const;
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return mkhash_add(marker, offset);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -171,10 +164,7 @@ public:
 | 
				
			||||||
		return multiple_ == other.multiple_;
 | 
							return multiple_ == other.multiple_;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int hash() const
 | 
						Hasher hash_into(Hasher h) const;
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
	   return multiple_.hash();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct DriveBit
 | 
					struct DriveBit
 | 
				
			||||||
| 
						 | 
					@ -362,35 +352,7 @@ public:
 | 
				
			||||||
		return *this;
 | 
							return *this;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int hash() const
 | 
						Hasher hash_into(Hasher h) 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);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool operator==(const DriveBit &other) const
 | 
						bool operator==(const DriveBit &other) const
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
| 
						 | 
					@ -511,10 +473,7 @@ struct DriveChunkWire
 | 
				
			||||||
		return offset < other.offset;
 | 
							return offset < other.offset;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int hash() const
 | 
						Hasher hash_into(Hasher h) const;
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return mkhash_add(mkhash(wire->name.hash(), width), offset);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	explicit operator SigChunk() const
 | 
						explicit operator SigChunk() const
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
| 
						 | 
					@ -572,10 +531,7 @@ struct DriveChunkPort
 | 
				
			||||||
		return offset < other.offset;
 | 
							return offset < other.offset;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int hash() const
 | 
						Hasher hash_into(Hasher h) const;
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return mkhash_add(mkhash(mkhash(cell->name.hash(), port.hash()), width), offset);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -616,10 +572,7 @@ struct DriveChunkMarker
 | 
				
			||||||
		return offset < other.offset;
 | 
							return offset < other.offset;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int hash() const
 | 
						Hasher hash_into(Hasher h) const;
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return mkhash_add(mkhash(marker, width), offset);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct DriveChunkMultiple
 | 
					struct DriveChunkMultiple
 | 
				
			||||||
| 
						 | 
					@ -659,10 +612,7 @@ public:
 | 
				
			||||||
		return false; // TODO implement, canonicalize order
 | 
							return false; // TODO implement, canonicalize order
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int hash() const
 | 
						Hasher hash_into(Hasher h) const;
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
	   return mkhash(width_, multiple_.hash());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct DriveChunk
 | 
					struct DriveChunk
 | 
				
			||||||
| 
						 | 
					@ -913,35 +863,7 @@ public:
 | 
				
			||||||
	bool try_append(DriveBit const &bit);
 | 
						bool try_append(DriveBit const &bit);
 | 
				
			||||||
	bool try_append(DriveChunk const &chunk);
 | 
						bool try_append(DriveChunk const &chunk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int hash() const
 | 
						Hasher hash_into(Hasher h) 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);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool operator==(const DriveChunk &other) const
 | 
						bool operator==(const DriveChunk &other) const
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
| 
						 | 
					@ -1144,17 +1066,20 @@ public:
 | 
				
			||||||
	DriveSpec &operator=(DriveBitMarker const &bit) { return *this = DriveBit(bit); }
 | 
						DriveSpec &operator=(DriveBitMarker const &bit) { return *this = DriveBit(bit); }
 | 
				
			||||||
	DriveSpec &operator=(DriveBitMultiple const &bit) { return *this = DriveBit(bit); }
 | 
						DriveSpec &operator=(DriveBitMultiple const &bit) { return *this = DriveBit(bit); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int hash() const {
 | 
						void updhash() const {
 | 
				
			||||||
		if (hash_ != 0) return hash_;
 | 
							if (hash_ != 0)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
		pack();
 | 
							pack();
 | 
				
			||||||
		hash_ = hash_ops<std::vector<DriveChunk>>().hash(chunks_);
 | 
							hash_ = run_hash(chunks_);
 | 
				
			||||||
		hash_ |= (hash_ == 0);
 | 
							hash_ |= (hash_ == 0);
 | 
				
			||||||
		return hash_;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Hasher hash_into(Hasher h) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool operator==(DriveSpec const &other) 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 false;
 | 
				
			||||||
		return chunks() == other.chunks();
 | 
							return chunks() == other.chunks();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1187,7 +1112,7 @@ 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; }
 | 
							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<DriveBitId, pool<DriveBitId>> but using less memory
 | 
						// Essentially a dict<DriveBitId, pool<DriveBitId>> but using less memory
 | 
				
			||||||
	// and fewer allocations
 | 
						// and fewer allocations
 | 
				
			||||||
| 
						 | 
					@ -1333,6 +1258,131 @@ private:
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline Hasher DriveBitWire::hash_into(Hasher h) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						h.eat(wire->name);
 | 
				
			||||||
 | 
						h.eat(offset);
 | 
				
			||||||
 | 
						return h;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline Hasher DriveBitPort::hash_into(Hasher h) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						h.eat(cell->name);
 | 
				
			||||||
 | 
						h.eat(port);
 | 
				
			||||||
 | 
						h.eat(offset);
 | 
				
			||||||
 | 
						return h;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline Hasher DriveBitMarker::hash_into(Hasher h) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						h.eat(marker);
 | 
				
			||||||
 | 
						h.eat(offset);
 | 
				
			||||||
 | 
						return h;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline Hasher DriveBitMultiple::hash_into(Hasher h) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						h.eat(multiple_);
 | 
				
			||||||
 | 
						return h;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline Hasher DriveBit::hash_into(Hasher h) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (type_) {
 | 
				
			||||||
 | 
						case DriveType::NONE:
 | 
				
			||||||
 | 
							h.eat(0);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case DriveType::CONSTANT:
 | 
				
			||||||
 | 
							h.eat(constant_);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case DriveType::WIRE:
 | 
				
			||||||
 | 
							h.eat(wire_);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case DriveType::PORT:
 | 
				
			||||||
 | 
							h.eat(port_);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case DriveType::MARKER:
 | 
				
			||||||
 | 
							h.eat(marker_);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case DriveType::MULTIPLE:
 | 
				
			||||||
 | 
							h.eat(multiple_);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						h.eat(type_);
 | 
				
			||||||
 | 
						return h;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline Hasher DriveChunkWire::hash_into(Hasher h) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						h.eat(wire->name);
 | 
				
			||||||
 | 
						h.eat(width);
 | 
				
			||||||
 | 
						h.eat(offset);
 | 
				
			||||||
 | 
						return h;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline Hasher DriveChunkPort::hash_into(Hasher h) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						h.eat(cell->name);
 | 
				
			||||||
 | 
						h.eat(port);
 | 
				
			||||||
 | 
						h.eat(width);
 | 
				
			||||||
 | 
						h.eat(offset);
 | 
				
			||||||
 | 
						return h;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline Hasher DriveChunkMarker::hash_into(Hasher h) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						h.eat(marker);
 | 
				
			||||||
 | 
						h.eat(width);
 | 
				
			||||||
 | 
						h.eat(offset);
 | 
				
			||||||
 | 
						return h;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline Hasher DriveChunkMultiple::hash_into(Hasher h) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						h.eat(width_);
 | 
				
			||||||
 | 
						h.eat(multiple_);
 | 
				
			||||||
 | 
						return h;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline Hasher DriveChunk::hash_into(Hasher h) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (type_) {
 | 
				
			||||||
 | 
						case DriveType::NONE:
 | 
				
			||||||
 | 
							h.eat(0);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case DriveType::CONSTANT:
 | 
				
			||||||
 | 
							h.eat(constant_);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case DriveType::WIRE:
 | 
				
			||||||
 | 
							h.eat(wire_);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case DriveType::PORT:
 | 
				
			||||||
 | 
							h.eat(port_);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case DriveType::MARKER:
 | 
				
			||||||
 | 
							h.eat(marker_);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case DriveType::MULTIPLE:
 | 
				
			||||||
 | 
							h.eat(multiple_);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						h.eat(type_);
 | 
				
			||||||
 | 
						return h;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline Hasher DriveSpec::hash_into(Hasher h) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						updhash();
 | 
				
			||||||
 | 
						h.eat(hash_);
 | 
				
			||||||
 | 
						return h;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline Hasher DriverMap::DriveBitId::hash_into(Hasher h) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						h.eat(id);
 | 
				
			||||||
 | 
						return h;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
YOSYS_NAMESPACE_END
 | 
					YOSYS_NAMESPACE_END
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -151,7 +151,7 @@ namespace Functional {
 | 
				
			||||||
		// returns the data width of a bitvector sort, errors out for other sorts
 | 
							// returns the data width of a bitvector sort, errors out for other sorts
 | 
				
			||||||
		int data_width() const { return std::get<1>(_v).second; }
 | 
							int data_width() const { return std::get<1>(_v).second; }
 | 
				
			||||||
		bool operator==(Sort const& other) const { return _v == other._v; }
 | 
							bool operator==(Sort const& other) const { return _v == other._v; }
 | 
				
			||||||
		unsigned int hash() const { return mkhash(_v); }
 | 
							Hasher hash_into(Hasher h) const { h.eat(_v); return h; }
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	class IR;
 | 
						class IR;
 | 
				
			||||||
	class Factory;
 | 
						class Factory;
 | 
				
			||||||
| 
						 | 
					@ -225,8 +225,10 @@ namespace Functional {
 | 
				
			||||||
			const RTLIL::Const &as_const() const { return std::get<RTLIL::Const>(_extra); }
 | 
								const RTLIL::Const &as_const() const { return std::get<RTLIL::Const>(_extra); }
 | 
				
			||||||
			std::pair<IdString, IdString> as_idstring_pair() const { return std::get<std::pair<IdString, IdString>>(_extra); }
 | 
								std::pair<IdString, IdString> as_idstring_pair() const { return std::get<std::pair<IdString, IdString>>(_extra); }
 | 
				
			||||||
			int as_int() const { return std::get<int>(_extra); }
 | 
								int as_int() const { return std::get<int>(_extra); }
 | 
				
			||||||
			int hash() const {
 | 
								Hasher hash_into(Hasher h) const {
 | 
				
			||||||
				return mkhash((unsigned int) _fn, mkhash(_extra));
 | 
									h.eat((unsigned int) _fn);
 | 
				
			||||||
 | 
									h.eat(_extra);
 | 
				
			||||||
 | 
									return h;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			bool operator==(NodeData const &other) const {
 | 
								bool operator==(NodeData const &other) const {
 | 
				
			||||||
				return _fn == other._fn && _extra == other._extra;
 | 
									return _fn == other._fn && _extra == other._extra;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										432
									
								
								kernel/hashlib.h
									
										
									
									
									
								
							
							
						
						
									
										432
									
								
								kernel/hashlib.h
									
										
									
									
									
								
							| 
						 | 
					@ -17,27 +17,62 @@
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <variant>
 | 
					#include <variant>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					#include <type_traits>
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define YS_HASHING_VERSION 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace hashlib {
 | 
					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.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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.
 | 
				
			||||||
 | 
					 * 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
 | 
				
			||||||
 | 
					 * still supported.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * HASH TABLES
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * We implement associative data structures with separate chaining.
 | 
				
			||||||
 | 
					 * Linked lists use integers into the indirection hashtable array
 | 
				
			||||||
 | 
					 * instead of pointers.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const int hashtable_size_trigger = 2;
 | 
					const int hashtable_size_trigger = 2;
 | 
				
			||||||
const int hashtable_size_factor = 3;
 | 
					const int hashtable_size_factor = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// The XOR version of DJB2
 | 
					namespace legacy {
 | 
				
			||||||
inline unsigned int mkhash(unsigned int a, unsigned int b) {
 | 
						inline uint32_t djb2_add(uint32_t a, uint32_t b) {
 | 
				
			||||||
	return ((a << 5) + a) ^ b;
 | 
							return ((a << 5) + a) + b;
 | 
				
			||||||
}
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// traditionally 5381 is used as starting value for the djb2 hash
 | 
					/**
 | 
				
			||||||
const unsigned int mkhash_init = 5381;
 | 
					 * Hash a type with an accumulator in a record or array context
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					template<typename T>
 | 
				
			||||||
 | 
					struct hash_ops;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// The ADD version of DJB2
 | 
					/**
 | 
				
			||||||
// (use this version for cache locality in b)
 | 
					 * Hash a single instance in isolation.
 | 
				
			||||||
inline unsigned int mkhash_add(unsigned int a, unsigned int b) {
 | 
					 * Can have explicit specialization, but the default redirects to hash_ops
 | 
				
			||||||
	return ((a << 5) + a) + b;
 | 
					 */
 | 
				
			||||||
}
 | 
					template<typename T>
 | 
				
			||||||
 | 
					struct hash_top_ops;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline unsigned int mkhash_xorshift(unsigned int a) {
 | 
					inline unsigned int mkhash_xorshift(unsigned int a) {
 | 
				
			||||||
	if (sizeof(a) == 4) {
 | 
						if (sizeof(a) == 4) {
 | 
				
			||||||
| 
						 | 
					@ -53,62 +88,100 @@ inline unsigned int mkhash_xorshift(unsigned int a) {
 | 
				
			||||||
	return a;
 | 
						return a;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename T> struct hash_ops {
 | 
					class HasherDJB32 {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						using hash_t = uint32_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						HasherDJB32() {
 | 
				
			||||||
 | 
							// traditionally 5381 is used as starting value for the djb2 hash
 | 
				
			||||||
 | 
							state = 5381;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						static void set_fudge(hash_t f) {
 | 
				
			||||||
 | 
							fudge = f;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						uint32_t state;
 | 
				
			||||||
 | 
						static uint32_t fudge;
 | 
				
			||||||
 | 
						// The XOR version of DJB2
 | 
				
			||||||
 | 
						[[nodiscard]]
 | 
				
			||||||
 | 
						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 = djb2_xor(i, state);
 | 
				
			||||||
 | 
							state = mkhash_xorshift(fudge ^ state);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						void hash64(uint64_t i) {
 | 
				
			||||||
 | 
							state = djb2_xor((uint32_t)(i & 0xFFFFFFFFULL), state);
 | 
				
			||||||
 | 
							state = djb2_xor((uint32_t)(i >> 32ULL), state);
 | 
				
			||||||
 | 
							state = mkhash_xorshift(fudge ^ state);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						[[nodiscard]]
 | 
				
			||||||
 | 
						hash_t yield() {
 | 
				
			||||||
 | 
							return (hash_t)state;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template<typename T>
 | 
				
			||||||
 | 
						void eat(T&& t) {
 | 
				
			||||||
 | 
							*this = hash_ops<std::remove_cv_t<std::remove_reference_t<T>>>::hash_into(std::forward<T>(t), *this);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template<typename T>
 | 
				
			||||||
 | 
						void eat(const T& t) {
 | 
				
			||||||
 | 
							*this = hash_ops<T>::hash_into(t, *this);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void commutative_eat(hash_t t) {
 | 
				
			||||||
 | 
							state ^= t;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void force(hash_t new_state) {
 | 
				
			||||||
 | 
							state = new_state;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Hasher = HasherDJB32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<typename T>
 | 
				
			||||||
 | 
					struct hash_top_ops {
 | 
				
			||||||
 | 
						static inline bool cmp(const T &a, const T &b) {
 | 
				
			||||||
 | 
							return hash_ops<T>::cmp(a, b);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						static inline Hasher hash(const T &a) {
 | 
				
			||||||
 | 
							return hash_ops<T>::hash_into(a, Hasher());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<typename T>
 | 
				
			||||||
 | 
					struct hash_ops {
 | 
				
			||||||
	static inline bool cmp(const T &a, const T &b) {
 | 
						static inline bool cmp(const T &a, const T &b) {
 | 
				
			||||||
		return a == b;
 | 
							return a == b;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	static inline unsigned int hash(const T &a) {
 | 
						static inline Hasher hash_into(const T &a, Hasher h) {
 | 
				
			||||||
		return a.hash();
 | 
							if constexpr (std::is_integral_v<T>) {
 | 
				
			||||||
	}
 | 
								static_assert(sizeof(T) <= sizeof(uint64_t));
 | 
				
			||||||
};
 | 
								if (sizeof(T) == sizeof(uint64_t))
 | 
				
			||||||
 | 
									h.hash64(a);
 | 
				
			||||||
struct hash_int_ops {
 | 
								else
 | 
				
			||||||
	template<typename T>
 | 
									h.hash32(a);
 | 
				
			||||||
	static inline bool cmp(T a, T b) {
 | 
								return h;
 | 
				
			||||||
		return a == b;
 | 
							} else if constexpr (std::is_enum_v<T>) {
 | 
				
			||||||
	}
 | 
								using u_type = std::underlying_type_t<T>;
 | 
				
			||||||
};
 | 
								return hash_ops<u_type>::hash_into((u_type) a, h);
 | 
				
			||||||
 | 
							} else if constexpr (std::is_pointer_v<T>) {
 | 
				
			||||||
template<> struct hash_ops<bool> : hash_int_ops
 | 
								return hash_ops<uintptr_t>::hash_into((uintptr_t) a, h);
 | 
				
			||||||
{
 | 
							} else if constexpr (std::is_same_v<T, std::string>) {
 | 
				
			||||||
	static inline unsigned int hash(bool a) {
 | 
								for (auto c : a)
 | 
				
			||||||
		return a ? 1 : 0;
 | 
									h.hash32(c);
 | 
				
			||||||
	}
 | 
								return h;
 | 
				
			||||||
};
 | 
							} else {
 | 
				
			||||||
template<> struct hash_ops<int32_t> : hash_int_ops
 | 
								return a.hash_into(h);
 | 
				
			||||||
{
 | 
							}
 | 
				
			||||||
	static inline unsigned int hash(int32_t a) {
 | 
					 | 
				
			||||||
		return a;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
template<> struct hash_ops<int64_t> : hash_int_ops
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	static inline unsigned int hash(int64_t a) {
 | 
					 | 
				
			||||||
		return mkhash((unsigned int)(a), (unsigned int)(a >> 32));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
template<> struct hash_ops<uint32_t> : hash_int_ops
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	static inline unsigned int hash(uint32_t a) {
 | 
					 | 
				
			||||||
		return a;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
template<> struct hash_ops<uint64_t> : hash_int_ops
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	static inline unsigned int hash(uint64_t a) {
 | 
					 | 
				
			||||||
		return mkhash((unsigned int)(a), (unsigned int)(a >> 32));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<> struct hash_ops<std::string> {
 | 
					 | 
				
			||||||
	static inline bool cmp(const std::string &a, const std::string &b) {
 | 
					 | 
				
			||||||
		return a == b;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	static inline unsigned int hash(const std::string &a) {
 | 
					 | 
				
			||||||
		unsigned int v = 0;
 | 
					 | 
				
			||||||
		for (auto c : a)
 | 
					 | 
				
			||||||
			v = mkhash(v, c);
 | 
					 | 
				
			||||||
		return v;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -116,8 +189,10 @@ template<typename P, typename Q> struct hash_ops<std::pair<P, Q>> {
 | 
				
			||||||
	static inline bool cmp(std::pair<P, Q> a, std::pair<P, Q> b) {
 | 
						static inline bool cmp(std::pair<P, Q> a, std::pair<P, Q> b) {
 | 
				
			||||||
		return a == b;
 | 
							return a == b;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	static inline unsigned int hash(std::pair<P, Q> a) {
 | 
						static inline Hasher hash_into(std::pair<P, Q> a, Hasher h) {
 | 
				
			||||||
		return mkhash(hash_ops<P>::hash(a.first), hash_ops<Q>::hash(a.second));
 | 
							h = hash_ops<P>::hash_into(a.first, h);
 | 
				
			||||||
 | 
							h = hash_ops<Q>::hash_into(a.second, h);
 | 
				
			||||||
 | 
							return h;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -126,13 +201,15 @@ template<typename... T> struct hash_ops<std::tuple<T...>> {
 | 
				
			||||||
		return a == b;
 | 
							return a == b;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	template<size_t I = 0>
 | 
						template<size_t I = 0>
 | 
				
			||||||
	static inline typename std::enable_if<I == sizeof...(T), unsigned int>::type hash(std::tuple<T...>) {
 | 
						static inline typename std::enable_if<I == sizeof...(T), Hasher>::type hash_into(std::tuple<T...>, Hasher h) {
 | 
				
			||||||
		return mkhash_init;
 | 
							return h;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	template<size_t I = 0>
 | 
						template<size_t I = 0>
 | 
				
			||||||
	static inline typename std::enable_if<I != sizeof...(T), unsigned int>::type hash(std::tuple<T...> a) {
 | 
						static inline typename std::enable_if<I != sizeof...(T), Hasher>::type hash_into(std::tuple<T...> a, Hasher h) {
 | 
				
			||||||
		typedef hash_ops<typename std::tuple_element<I, std::tuple<T...>>::type> element_ops_t;
 | 
							typedef hash_ops<typename std::tuple_element<I, std::tuple<T...>>::type> element_ops_t;
 | 
				
			||||||
		return mkhash(hash<I+1>(a), element_ops_t::hash(std::get<I>(a)));
 | 
							h = hash_into<I+1>(a, h);
 | 
				
			||||||
 | 
							h = element_ops_t::hash_into(std::get<I>(a), h);
 | 
				
			||||||
 | 
							return h;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -140,35 +217,44 @@ template<typename T> struct hash_ops<std::vector<T>> {
 | 
				
			||||||
	static inline bool cmp(std::vector<T> a, std::vector<T> b) {
 | 
						static inline bool cmp(std::vector<T> a, std::vector<T> b) {
 | 
				
			||||||
		return a == b;
 | 
							return a == b;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	static inline unsigned int hash(std::vector<T> a) {
 | 
						static inline Hasher hash_into(std::vector<T> a, Hasher h) {
 | 
				
			||||||
		unsigned int h = mkhash_init;
 | 
							h.eat((uint32_t)a.size());
 | 
				
			||||||
		for (auto k : a)
 | 
							for (auto k : a)
 | 
				
			||||||
			h = mkhash(h, hash_ops<T>::hash(k));
 | 
								h.eat(k);
 | 
				
			||||||
		return h;
 | 
							return h;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<typename T, size_t N> struct hash_ops<std::array<T, N>> {
 | 
				
			||||||
 | 
					    static inline bool cmp(std::array<T, N> a, std::array<T, N> b) {
 | 
				
			||||||
 | 
					        return a == b;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    static inline Hasher hash_into(std::array<T, N> a, Hasher h) {
 | 
				
			||||||
 | 
					        for (const auto& k : a)
 | 
				
			||||||
 | 
					            h = hash_ops<T>::hash_into(k, h);
 | 
				
			||||||
 | 
					        return h;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct hash_cstr_ops {
 | 
					struct hash_cstr_ops {
 | 
				
			||||||
	static inline bool cmp(const char *a, const char *b) {
 | 
						static inline bool cmp(const char *a, const char *b) {
 | 
				
			||||||
		for (int i = 0; a[i] || b[i]; i++)
 | 
							return strcmp(a, b) == 0;
 | 
				
			||||||
			if (a[i] != b[i])
 | 
					 | 
				
			||||||
				return false;
 | 
					 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	static inline unsigned int hash(const char *a) {
 | 
						static inline Hasher hash_into(const char *a, Hasher h) {
 | 
				
			||||||
		unsigned int hash = mkhash_init;
 | 
					 | 
				
			||||||
		while (*a)
 | 
							while (*a)
 | 
				
			||||||
			hash = mkhash(hash, *(a++));
 | 
								h.hash32(*(a++));
 | 
				
			||||||
		return hash;
 | 
							return h;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <> struct hash_ops<char*> : hash_cstr_ops {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct hash_ptr_ops {
 | 
					struct hash_ptr_ops {
 | 
				
			||||||
	static inline bool cmp(const void *a, const void *b) {
 | 
						static inline bool cmp(const void *a, const void *b) {
 | 
				
			||||||
		return a == b;
 | 
							return a == b;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	static inline unsigned int hash(const void *a) {
 | 
						static inline Hasher hash_into(const void *a, Hasher h) {
 | 
				
			||||||
		return (uintptr_t)a;
 | 
							return hash_ops<uintptr_t>::hash_into((uintptr_t)a, h);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -177,22 +263,40 @@ struct hash_obj_ops {
 | 
				
			||||||
		return a == b;
 | 
							return a == b;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	template<typename T>
 | 
						template<typename T>
 | 
				
			||||||
	static inline unsigned int hash(const T *a) {
 | 
						static inline Hasher hash_into(const T *a, Hasher h) {
 | 
				
			||||||
		return a ? a->hash() : 0;
 | 
							if (a)
 | 
				
			||||||
 | 
								a->hash_into(h);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								h.eat(0);
 | 
				
			||||||
 | 
							return 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<typename T>
 | 
					template<typename T>
 | 
				
			||||||
 | 
					[[nodiscard]]
 | 
				
			||||||
 | 
					Hasher::hash_t run_hash(const T& obj) {
 | 
				
			||||||
 | 
						return hash_top_ops<T>::hash(obj).yield();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Refer to docs/source/yosys_internals/hashing.rst */
 | 
				
			||||||
 | 
					template<typename T>
 | 
				
			||||||
 | 
					[[nodiscard]]
 | 
				
			||||||
 | 
					[[deprecated]]
 | 
				
			||||||
inline unsigned int mkhash(const T &v) {
 | 
					inline unsigned int mkhash(const T &v) {
 | 
				
			||||||
	return hash_ops<T>().hash(v);
 | 
						return (unsigned int) run_hash<T>(v);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<> struct hash_ops<std::monostate> {
 | 
					template<> struct hash_ops<std::monostate> {
 | 
				
			||||||
	static inline bool cmp(std::monostate a, std::monostate b) {
 | 
						static inline bool cmp(std::monostate a, std::monostate b) {
 | 
				
			||||||
		return a == b;
 | 
							return a == b;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	static inline unsigned int hash(std::monostate) {
 | 
						static inline Hasher hash_into(std::monostate, Hasher h) {
 | 
				
			||||||
		return mkhash_init;
 | 
							return h;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -200,9 +304,10 @@ template<typename... T> struct hash_ops<std::variant<T...>> {
 | 
				
			||||||
	static inline bool cmp(std::variant<T...> a, std::variant<T...> b) {
 | 
						static inline bool cmp(std::variant<T...> a, std::variant<T...> b) {
 | 
				
			||||||
		return a == b;
 | 
							return a == b;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	static inline unsigned int hash(std::variant<T...> a) {
 | 
						static inline Hasher hash_into(std::variant<T...> a, Hasher h) {
 | 
				
			||||||
		unsigned int h = std::visit([](const auto &v) { return mkhash(v); }, a);
 | 
							std::visit([& h](const auto &v) { h.eat(v); }, a);
 | 
				
			||||||
		return mkhash(a.index(), h);
 | 
							h.eat(a.index());
 | 
				
			||||||
 | 
							return h;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -210,11 +315,12 @@ template<typename T> struct hash_ops<std::optional<T>> {
 | 
				
			||||||
	static inline bool cmp(std::optional<T> a, std::optional<T> b) {
 | 
						static inline bool cmp(std::optional<T> a, std::optional<T> b) {
 | 
				
			||||||
		return a == b;
 | 
							return a == b;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	static inline unsigned int hash(std::optional<T> a) {
 | 
						static inline Hasher hash_into(std::optional<T> a, Hasher h) {
 | 
				
			||||||
		if(a.has_value())
 | 
							if(a.has_value())
 | 
				
			||||||
			return mkhash(*a);
 | 
								h.eat(*a);
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			return 0;
 | 
								h.eat(0);
 | 
				
			||||||
 | 
							return h;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -246,14 +352,13 @@ inline int hashtable_size(int min_size)
 | 
				
			||||||
	throw std::length_error("hash table exceeded maximum size.");
 | 
						throw std::length_error("hash table exceeded maximum size.");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename K, typename T, typename OPS = hash_ops<K>> class dict;
 | 
					template<typename K, typename T, typename OPS = hash_top_ops<K>> class dict;
 | 
				
			||||||
template<typename K, int offset = 0, typename OPS = hash_ops<K>> class idict;
 | 
					template<typename K, int offset = 0, typename OPS = hash_top_ops<K>> class idict;
 | 
				
			||||||
template<typename K, typename OPS = hash_ops<K>> class pool;
 | 
					template<typename K, typename OPS = hash_top_ops<K>> class pool;
 | 
				
			||||||
template<typename K, typename OPS = hash_ops<K>> class mfp;
 | 
					template<typename K, typename OPS = hash_top_ops<K>> class mfp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename K, typename T, typename OPS>
 | 
					template<typename K, typename T, typename OPS>
 | 
				
			||||||
class dict
 | 
					class dict {
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct entry_t
 | 
						struct entry_t
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		std::pair<K, T> udata;
 | 
							std::pair<K, T> udata;
 | 
				
			||||||
| 
						 | 
					@ -277,11 +382,11 @@ class dict
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int do_hash(const K &key) const
 | 
						Hasher::hash_t do_hash(const K &key) const
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		unsigned int hash = 0;
 | 
							Hasher::hash_t hash = 0;
 | 
				
			||||||
		if (!hashtable.empty())
 | 
							if (!hashtable.empty())
 | 
				
			||||||
			hash = ops.hash(key) % (unsigned int)(hashtable.size());
 | 
								hash = ops.hash(key).yield() % (unsigned int)(hashtable.size());
 | 
				
			||||||
		return hash;
 | 
							return hash;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -292,13 +397,13 @@ class dict
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (int i = 0; i < int(entries.size()); i++) {
 | 
							for (int i = 0; i < int(entries.size()); i++) {
 | 
				
			||||||
			do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));
 | 
								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];
 | 
								entries[i].next = hashtable[hash];
 | 
				
			||||||
			hashtable[hash] = i;
 | 
								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()));
 | 
							do_assert(index < int(entries.size()));
 | 
				
			||||||
		if (hashtable.empty() || index < 0)
 | 
							if (hashtable.empty() || index < 0)
 | 
				
			||||||
| 
						 | 
					@ -321,7 +426,7 @@ class dict
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (index != back_idx)
 | 
							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];
 | 
								k = hashtable[back_hash];
 | 
				
			||||||
			do_assert(0 <= k && k < int(entries.size()));
 | 
								do_assert(0 <= k && k < int(entries.size()));
 | 
				
			||||||
| 
						 | 
					@ -347,7 +452,7 @@ class dict
 | 
				
			||||||
		return 1;
 | 
							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())
 | 
							if (hashtable.empty())
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
| 
						 | 
					@ -367,7 +472,7 @@ class dict
 | 
				
			||||||
		return index;
 | 
							return index;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int do_insert(const K &key, int &hash)
 | 
						int do_insert(const K &key, Hasher::hash_t &hash)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (hashtable.empty()) {
 | 
							if (hashtable.empty()) {
 | 
				
			||||||
			entries.emplace_back(std::pair<K, T>(key, T()), -1);
 | 
								entries.emplace_back(std::pair<K, T>(key, T()), -1);
 | 
				
			||||||
| 
						 | 
					@ -380,7 +485,7 @@ class dict
 | 
				
			||||||
		return entries.size() - 1;
 | 
							return entries.size() - 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int do_insert(const std::pair<K, T> &value, int &hash)
 | 
						int do_insert(const std::pair<K, T> &value, Hasher::hash_t &hash)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (hashtable.empty()) {
 | 
							if (hashtable.empty()) {
 | 
				
			||||||
			entries.emplace_back(value, -1);
 | 
								entries.emplace_back(value, -1);
 | 
				
			||||||
| 
						 | 
					@ -393,7 +498,7 @@ class dict
 | 
				
			||||||
		return entries.size() - 1;
 | 
							return entries.size() - 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int do_insert(std::pair<K, T> &&rvalue, int &hash)
 | 
						int do_insert(std::pair<K, T> &&rvalue, Hasher::hash_t &hash)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (hashtable.empty()) {
 | 
							if (hashtable.empty()) {
 | 
				
			||||||
			auto key = rvalue.first;
 | 
								auto key = rvalue.first;
 | 
				
			||||||
| 
						 | 
					@ -505,7 +610,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::pair<iterator, bool> insert(const K &key)
 | 
						std::pair<iterator, bool> insert(const K &key)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int hash = do_hash(key);
 | 
							Hasher::hash_t hash = do_hash(key);
 | 
				
			||||||
		int i = do_lookup(key, hash);
 | 
							int i = do_lookup(key, hash);
 | 
				
			||||||
		if (i >= 0)
 | 
							if (i >= 0)
 | 
				
			||||||
			return std::pair<iterator, bool>(iterator(this, i), false);
 | 
								return std::pair<iterator, bool>(iterator(this, i), false);
 | 
				
			||||||
| 
						 | 
					@ -515,7 +620,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::pair<iterator, bool> insert(const std::pair<K, T> &value)
 | 
						std::pair<iterator, bool> insert(const std::pair<K, T> &value)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int hash = do_hash(value.first);
 | 
							Hasher::hash_t hash = do_hash(value.first);
 | 
				
			||||||
		int i = do_lookup(value.first, hash);
 | 
							int i = do_lookup(value.first, hash);
 | 
				
			||||||
		if (i >= 0)
 | 
							if (i >= 0)
 | 
				
			||||||
			return std::pair<iterator, bool>(iterator(this, i), false);
 | 
								return std::pair<iterator, bool>(iterator(this, i), false);
 | 
				
			||||||
| 
						 | 
					@ -525,7 +630,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::pair<iterator, bool> insert(std::pair<K, T> &&rvalue)
 | 
						std::pair<iterator, bool> insert(std::pair<K, T> &&rvalue)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int hash = do_hash(rvalue.first);
 | 
							Hasher::hash_t hash = do_hash(rvalue.first);
 | 
				
			||||||
		int i = do_lookup(rvalue.first, hash);
 | 
							int i = do_lookup(rvalue.first, hash);
 | 
				
			||||||
		if (i >= 0)
 | 
							if (i >= 0)
 | 
				
			||||||
			return std::pair<iterator, bool>(iterator(this, i), false);
 | 
								return std::pair<iterator, bool>(iterator(this, i), false);
 | 
				
			||||||
| 
						 | 
					@ -535,7 +640,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::pair<iterator, bool> emplace(K const &key, T const &value)
 | 
						std::pair<iterator, bool> 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);
 | 
							int i = do_lookup(key, hash);
 | 
				
			||||||
		if (i >= 0)
 | 
							if (i >= 0)
 | 
				
			||||||
			return std::pair<iterator, bool>(iterator(this, i), false);
 | 
								return std::pair<iterator, bool>(iterator(this, i), false);
 | 
				
			||||||
| 
						 | 
					@ -545,7 +650,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::pair<iterator, bool> emplace(K const &key, T &&rvalue)
 | 
						std::pair<iterator, bool> emplace(K const &key, T &&rvalue)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int hash = do_hash(key);
 | 
							Hasher::hash_t hash = do_hash(key);
 | 
				
			||||||
		int i = do_lookup(key, hash);
 | 
							int i = do_lookup(key, hash);
 | 
				
			||||||
		if (i >= 0)
 | 
							if (i >= 0)
 | 
				
			||||||
			return std::pair<iterator, bool>(iterator(this, i), false);
 | 
								return std::pair<iterator, bool>(iterator(this, i), false);
 | 
				
			||||||
| 
						 | 
					@ -555,7 +660,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::pair<iterator, bool> emplace(K &&rkey, T const &value)
 | 
						std::pair<iterator, bool> emplace(K &&rkey, T const &value)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int hash = do_hash(rkey);
 | 
							Hasher::hash_t hash = do_hash(rkey);
 | 
				
			||||||
		int i = do_lookup(rkey, hash);
 | 
							int i = do_lookup(rkey, hash);
 | 
				
			||||||
		if (i >= 0)
 | 
							if (i >= 0)
 | 
				
			||||||
			return std::pair<iterator, bool>(iterator(this, i), false);
 | 
								return std::pair<iterator, bool>(iterator(this, i), false);
 | 
				
			||||||
| 
						 | 
					@ -565,7 +670,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::pair<iterator, bool> emplace(K &&rkey, T &&rvalue)
 | 
						std::pair<iterator, bool> emplace(K &&rkey, T &&rvalue)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int hash = do_hash(rkey);
 | 
							Hasher::hash_t hash = do_hash(rkey);
 | 
				
			||||||
		int i = do_lookup(rkey, hash);
 | 
							int i = do_lookup(rkey, hash);
 | 
				
			||||||
		if (i >= 0)
 | 
							if (i >= 0)
 | 
				
			||||||
			return std::pair<iterator, bool>(iterator(this, i), false);
 | 
								return std::pair<iterator, bool>(iterator(this, i), false);
 | 
				
			||||||
| 
						 | 
					@ -575,35 +680,35 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int erase(const K &key)
 | 
						int erase(const K &key)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int hash = do_hash(key);
 | 
							Hasher::hash_t hash = do_hash(key);
 | 
				
			||||||
		int index = do_lookup(key, hash);
 | 
							int index = do_lookup(key, hash);
 | 
				
			||||||
		return do_erase(index, hash);
 | 
							return do_erase(index, hash);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iterator erase(iterator it)
 | 
						iterator erase(iterator it)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int hash = do_hash(it->first);
 | 
							Hasher::hash_t hash = do_hash(it->first);
 | 
				
			||||||
		do_erase(it.index, hash);
 | 
							do_erase(it.index, hash);
 | 
				
			||||||
		return ++it;
 | 
							return ++it;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int count(const K &key) const
 | 
						int count(const K &key) const
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int hash = do_hash(key);
 | 
							Hasher::hash_t hash = do_hash(key);
 | 
				
			||||||
		int i = do_lookup(key, hash);
 | 
							int i = do_lookup(key, hash);
 | 
				
			||||||
		return i < 0 ? 0 : 1;
 | 
							return i < 0 ? 0 : 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int count(const K &key, const_iterator it) const
 | 
						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);
 | 
							int i = do_lookup(key, hash);
 | 
				
			||||||
		return i < 0 || i > it.index ? 0 : 1;
 | 
							return i < 0 || i > it.index ? 0 : 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iterator find(const K &key)
 | 
						iterator find(const K &key)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int hash = do_hash(key);
 | 
							Hasher::hash_t hash = do_hash(key);
 | 
				
			||||||
		int i = do_lookup(key, hash);
 | 
							int i = do_lookup(key, hash);
 | 
				
			||||||
		if (i < 0)
 | 
							if (i < 0)
 | 
				
			||||||
			return end();
 | 
								return end();
 | 
				
			||||||
| 
						 | 
					@ -612,7 +717,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const_iterator find(const K &key) const
 | 
						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);
 | 
							int i = do_lookup(key, hash);
 | 
				
			||||||
		if (i < 0)
 | 
							if (i < 0)
 | 
				
			||||||
			return end();
 | 
								return end();
 | 
				
			||||||
| 
						 | 
					@ -621,7 +726,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	T& at(const K &key)
 | 
						T& at(const K &key)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int hash = do_hash(key);
 | 
							Hasher::hash_t hash = do_hash(key);
 | 
				
			||||||
		int i = do_lookup(key, hash);
 | 
							int i = do_lookup(key, hash);
 | 
				
			||||||
		if (i < 0)
 | 
							if (i < 0)
 | 
				
			||||||
			throw std::out_of_range("dict::at()");
 | 
								throw std::out_of_range("dict::at()");
 | 
				
			||||||
| 
						 | 
					@ -630,7 +735,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const T& at(const K &key) const
 | 
						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);
 | 
							int i = do_lookup(key, hash);
 | 
				
			||||||
		if (i < 0)
 | 
							if (i < 0)
 | 
				
			||||||
			throw std::out_of_range("dict::at()");
 | 
								throw std::out_of_range("dict::at()");
 | 
				
			||||||
| 
						 | 
					@ -639,7 +744,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const T& at(const K &key, const T &defval) const
 | 
						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);
 | 
							int i = do_lookup(key, hash);
 | 
				
			||||||
		if (i < 0)
 | 
							if (i < 0)
 | 
				
			||||||
			return defval;
 | 
								return defval;
 | 
				
			||||||
| 
						 | 
					@ -648,7 +753,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	T& operator[](const K &key)
 | 
						T& operator[](const K &key)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int hash = do_hash(key);
 | 
							Hasher::hash_t hash = do_hash(key);
 | 
				
			||||||
		int i = do_lookup(key, hash);
 | 
							int i = do_lookup(key, hash);
 | 
				
			||||||
		if (i < 0)
 | 
							if (i < 0)
 | 
				
			||||||
			i = do_insert(std::pair<K, T>(key, T()), hash);
 | 
								i = do_insert(std::pair<K, T>(key, T()), hash);
 | 
				
			||||||
| 
						 | 
					@ -683,12 +788,14 @@ public:
 | 
				
			||||||
		return !operator==(other);
 | 
							return !operator==(other);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int hash() const {
 | 
						Hasher hash_into(Hasher h) const {
 | 
				
			||||||
		unsigned int h = mkhash_init;
 | 
							for (auto &it : entries) {
 | 
				
			||||||
		for (auto &entry : entries) {
 | 
								Hasher entry_hash;
 | 
				
			||||||
			h ^= hash_ops<K>::hash(entry.udata.first);
 | 
								entry_hash.eat(it.udata.first);
 | 
				
			||||||
			h ^= hash_ops<T>::hash(entry.udata.second);
 | 
								entry_hash.eat(it.udata.second);
 | 
				
			||||||
 | 
								h.commutative_eat(entry_hash.yield());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							h.eat(entries.size());
 | 
				
			||||||
		return h;
 | 
							return h;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -734,11 +841,11 @@ protected:
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int do_hash(const K &key) const
 | 
						Hasher::hash_t do_hash(const K &key) const
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		unsigned int hash = 0;
 | 
							Hasher::hash_t hash = 0;
 | 
				
			||||||
		if (!hashtable.empty())
 | 
							if (!hashtable.empty())
 | 
				
			||||||
			hash = ops.hash(key) % (unsigned int)(hashtable.size());
 | 
								hash = ops.hash(key).yield() % (unsigned int)(hashtable.size());
 | 
				
			||||||
		return hash;
 | 
							return hash;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -749,13 +856,13 @@ protected:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (int i = 0; i < int(entries.size()); i++) {
 | 
							for (int i = 0; i < int(entries.size()); i++) {
 | 
				
			||||||
			do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));
 | 
								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];
 | 
								entries[i].next = hashtable[hash];
 | 
				
			||||||
			hashtable[hash] = i;
 | 
								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()));
 | 
							do_assert(index < int(entries.size()));
 | 
				
			||||||
		if (hashtable.empty() || index < 0)
 | 
							if (hashtable.empty() || index < 0)
 | 
				
			||||||
| 
						 | 
					@ -776,7 +883,7 @@ protected:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (index != back_idx)
 | 
							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];
 | 
								k = hashtable[back_hash];
 | 
				
			||||||
			if (k == back_idx) {
 | 
								if (k == back_idx) {
 | 
				
			||||||
| 
						 | 
					@ -800,7 +907,7 @@ protected:
 | 
				
			||||||
		return 1;
 | 
							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())
 | 
							if (hashtable.empty())
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
| 
						 | 
					@ -820,7 +927,7 @@ protected:
 | 
				
			||||||
		return index;
 | 
							return index;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int do_insert(const K &value, int &hash)
 | 
						int do_insert(const K &value, Hasher::hash_t &hash)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (hashtable.empty()) {
 | 
							if (hashtable.empty()) {
 | 
				
			||||||
			entries.emplace_back(value, -1);
 | 
								entries.emplace_back(value, -1);
 | 
				
			||||||
| 
						 | 
					@ -833,7 +940,7 @@ protected:
 | 
				
			||||||
		return entries.size() - 1;
 | 
							return entries.size() - 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int do_insert(K &&rvalue, int &hash)
 | 
						int do_insert(K &&rvalue, Hasher::hash_t &hash)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (hashtable.empty()) {
 | 
							if (hashtable.empty()) {
 | 
				
			||||||
			entries.emplace_back(std::forward<K>(rvalue), -1);
 | 
								entries.emplace_back(std::forward<K>(rvalue), -1);
 | 
				
			||||||
| 
						 | 
					@ -940,7 +1047,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::pair<iterator, bool> insert(const K &value)
 | 
						std::pair<iterator, bool> insert(const K &value)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int hash = do_hash(value);
 | 
							Hasher::hash_t hash = do_hash(value);
 | 
				
			||||||
		int i = do_lookup(value, hash);
 | 
							int i = do_lookup(value, hash);
 | 
				
			||||||
		if (i >= 0)
 | 
							if (i >= 0)
 | 
				
			||||||
			return std::pair<iterator, bool>(iterator(this, i), false);
 | 
								return std::pair<iterator, bool>(iterator(this, i), false);
 | 
				
			||||||
| 
						 | 
					@ -950,7 +1057,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::pair<iterator, bool> insert(K &&rvalue)
 | 
						std::pair<iterator, bool> insert(K &&rvalue)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int hash = do_hash(rvalue);
 | 
							Hasher::hash_t hash = do_hash(rvalue);
 | 
				
			||||||
		int i = do_lookup(rvalue, hash);
 | 
							int i = do_lookup(rvalue, hash);
 | 
				
			||||||
		if (i >= 0)
 | 
							if (i >= 0)
 | 
				
			||||||
			return std::pair<iterator, bool>(iterator(this, i), false);
 | 
								return std::pair<iterator, bool>(iterator(this, i), false);
 | 
				
			||||||
| 
						 | 
					@ -966,35 +1073,35 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int erase(const K &key)
 | 
						int erase(const K &key)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int hash = do_hash(key);
 | 
							Hasher::hash_t hash = do_hash(key);
 | 
				
			||||||
		int index = do_lookup(key, hash);
 | 
							int index = do_lookup(key, hash);
 | 
				
			||||||
		return do_erase(index, hash);
 | 
							return do_erase(index, hash);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iterator erase(iterator it)
 | 
						iterator erase(iterator it)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int hash = do_hash(*it);
 | 
							Hasher::hash_t hash = do_hash(*it);
 | 
				
			||||||
		do_erase(it.index, hash);
 | 
							do_erase(it.index, hash);
 | 
				
			||||||
		return ++it;
 | 
							return ++it;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int count(const K &key) const
 | 
						int count(const K &key) const
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int hash = do_hash(key);
 | 
							Hasher::hash_t hash = do_hash(key);
 | 
				
			||||||
		int i = do_lookup(key, hash);
 | 
							int i = do_lookup(key, hash);
 | 
				
			||||||
		return i < 0 ? 0 : 1;
 | 
							return i < 0 ? 0 : 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int count(const K &key, const_iterator it) const
 | 
						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);
 | 
							int i = do_lookup(key, hash);
 | 
				
			||||||
		return i < 0 || i > it.index ? 0 : 1;
 | 
							return i < 0 || i > it.index ? 0 : 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iterator find(const K &key)
 | 
						iterator find(const K &key)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int hash = do_hash(key);
 | 
							Hasher::hash_t hash = do_hash(key);
 | 
				
			||||||
		int i = do_lookup(key, hash);
 | 
							int i = do_lookup(key, hash);
 | 
				
			||||||
		if (i < 0)
 | 
							if (i < 0)
 | 
				
			||||||
			return end();
 | 
								return end();
 | 
				
			||||||
| 
						 | 
					@ -1003,7 +1110,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const_iterator find(const K &key) const
 | 
						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);
 | 
							int i = do_lookup(key, hash);
 | 
				
			||||||
		if (i < 0)
 | 
							if (i < 0)
 | 
				
			||||||
			return end();
 | 
								return end();
 | 
				
			||||||
| 
						 | 
					@ -1012,7 +1119,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool operator[](const K &key)
 | 
						bool operator[](const K &key)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int hash = do_hash(key);
 | 
							Hasher::hash_t hash = do_hash(key);
 | 
				
			||||||
		int i = do_lookup(key, hash);
 | 
							int i = do_lookup(key, hash);
 | 
				
			||||||
		return i >= 0;
 | 
							return i >= 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1051,11 +1158,12 @@ public:
 | 
				
			||||||
		return !operator==(other);
 | 
							return !operator==(other);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int hash() const {
 | 
						Hasher hash_into(Hasher h) const {
 | 
				
			||||||
		unsigned int hashval = mkhash_init;
 | 
							for (auto &it : entries) {
 | 
				
			||||||
		for (auto &it : entries)
 | 
								h.commutative_eat(ops.hash(it.udata).yield());
 | 
				
			||||||
			hashval ^= ops.hash(it.udata);
 | 
							}
 | 
				
			||||||
		return hashval;
 | 
							h.eat(entries.size());
 | 
				
			||||||
 | 
							return h;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void reserve(size_t n) { entries.reserve(n); }
 | 
						void reserve(size_t n) { entries.reserve(n); }
 | 
				
			||||||
| 
						 | 
					@ -1105,7 +1213,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int operator()(const K &key)
 | 
						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);
 | 
							int i = database.do_lookup(key, hash);
 | 
				
			||||||
		if (i < 0)
 | 
							if (i < 0)
 | 
				
			||||||
			i = database.do_insert(key, hash);
 | 
								i = database.do_insert(key, hash);
 | 
				
			||||||
| 
						 | 
					@ -1114,7 +1222,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int at(const K &key) const
 | 
						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);
 | 
							int i = database.do_lookup(key, hash);
 | 
				
			||||||
		if (i < 0)
 | 
							if (i < 0)
 | 
				
			||||||
			throw std::out_of_range("idict::at()");
 | 
								throw std::out_of_range("idict::at()");
 | 
				
			||||||
| 
						 | 
					@ -1123,7 +1231,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int at(const K &key, int defval) const
 | 
						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);
 | 
							int i = database.do_lookup(key, hash);
 | 
				
			||||||
		if (i < 0)
 | 
							if (i < 0)
 | 
				
			||||||
			return defval;
 | 
								return defval;
 | 
				
			||||||
| 
						 | 
					@ -1132,7 +1240,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int count(const K &key) const
 | 
						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);
 | 
							int i = database.do_lookup(key, hash);
 | 
				
			||||||
		return i < 0 ? 0 : 1;
 | 
							return i < 0 ? 0 : 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1176,7 +1284,7 @@ class mfp
 | 
				
			||||||
	mutable std::vector<int> parents;
 | 
						mutable std::vector<int> parents;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	typedef typename idict<K, 0, OPS>::const_iterator const_iterator;
 | 
						typedef typename idict<K, 0>::const_iterator const_iterator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	constexpr mfp()
 | 
						constexpr mfp()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								kernel/log.h
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								kernel/log.h
									
										
									
									
									
								
							| 
						 | 
					@ -367,13 +367,13 @@ void log_dump_val_worker(RTLIL::IdString v);
 | 
				
			||||||
void log_dump_val_worker(RTLIL::SigSpec v);
 | 
					void log_dump_val_worker(RTLIL::SigSpec v);
 | 
				
			||||||
void log_dump_val_worker(RTLIL::State v);
 | 
					void log_dump_val_worker(RTLIL::State v);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename K, typename T, typename OPS> static inline void log_dump_val_worker(dict<K, T, OPS> &v);
 | 
					template<typename K, typename T> static inline void log_dump_val_worker(dict<K, T> &v);
 | 
				
			||||||
template<typename K, typename OPS> static inline void log_dump_val_worker(pool<K, OPS> &v);
 | 
					template<typename K> static inline void log_dump_val_worker(pool<K> &v);
 | 
				
			||||||
template<typename K> static inline void log_dump_val_worker(std::vector<K> &v);
 | 
					template<typename K> static inline void log_dump_val_worker(std::vector<K> &v);
 | 
				
			||||||
template<typename T> static inline void log_dump_val_worker(T *ptr);
 | 
					template<typename T> static inline void log_dump_val_worker(T *ptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename K, typename T, typename OPS>
 | 
					template<typename K, typename T>
 | 
				
			||||||
static inline void log_dump_val_worker(dict<K, T, OPS> &v) {
 | 
					static inline void log_dump_val_worker(dict<K, T> &v) {
 | 
				
			||||||
	log("{");
 | 
						log("{");
 | 
				
			||||||
	bool first = true;
 | 
						bool first = true;
 | 
				
			||||||
	for (auto &it : v) {
 | 
						for (auto &it : v) {
 | 
				
			||||||
| 
						 | 
					@ -386,8 +386,8 @@ static inline void log_dump_val_worker(dict<K, T, OPS> &v) {
 | 
				
			||||||
	log(" }");
 | 
						log(" }");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename K, typename OPS>
 | 
					template<typename K>
 | 
				
			||||||
static inline void log_dump_val_worker(pool<K, OPS> &v) {
 | 
					static inline void log_dump_val_worker(pool<K> &v) {
 | 
				
			||||||
	log("{");
 | 
						log("{");
 | 
				
			||||||
	bool first = true;
 | 
						bool first = true;
 | 
				
			||||||
	for (auto &it : v) {
 | 
						for (auto &it : v) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,8 +48,11 @@ struct ModIndex : public RTLIL::Monitor
 | 
				
			||||||
			return cell == other.cell && port == other.port && offset == other.offset;
 | 
								return cell == other.cell && port == other.port && offset == other.offset;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		unsigned int hash() const {
 | 
							Hasher hash_into(Hasher h) const {
 | 
				
			||||||
			return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset);
 | 
								h.eat(cell->name);
 | 
				
			||||||
 | 
								h.eat(port);
 | 
				
			||||||
 | 
								h.eat(offset);
 | 
				
			||||||
 | 
								return h;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -304,6 +307,7 @@ struct ModWalker
 | 
				
			||||||
		RTLIL::Cell *cell;
 | 
							RTLIL::Cell *cell;
 | 
				
			||||||
		RTLIL::IdString port;
 | 
							RTLIL::IdString port;
 | 
				
			||||||
		int offset;
 | 
							int offset;
 | 
				
			||||||
 | 
							PortBit(Cell* c, IdString p, int o) : cell(c), port(p), offset(o) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bool operator<(const PortBit &other) const {
 | 
							bool operator<(const PortBit &other) const {
 | 
				
			||||||
			if (cell != other.cell)
 | 
								if (cell != other.cell)
 | 
				
			||||||
| 
						 | 
					@ -317,8 +321,11 @@ struct ModWalker
 | 
				
			||||||
			return cell == other.cell && port == other.port && offset == other.offset;
 | 
								return cell == other.cell && port == other.port && offset == other.offset;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		unsigned int hash() const {
 | 
							Hasher hash_into(Hasher h) const {
 | 
				
			||||||
			return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset);
 | 
								h.eat(cell->name);
 | 
				
			||||||
 | 
								h.eat(port);
 | 
				
			||||||
 | 
								h.eat(offset);
 | 
				
			||||||
 | 
								return h;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -355,7 +362,7 @@ struct ModWalker
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		for (int i = 0; i < int(bits.size()); i++)
 | 
							for (int i = 0; i < int(bits.size()); i++)
 | 
				
			||||||
			if (bits[i].wire != NULL) {
 | 
								if (bits[i].wire != NULL) {
 | 
				
			||||||
				PortBit pbit = { cell, port, i };
 | 
									PortBit pbit {cell, port, i};
 | 
				
			||||||
				if (is_output) {
 | 
									if (is_output) {
 | 
				
			||||||
					signal_drivers[bits[i]].insert(pbit);
 | 
										signal_drivers[bits[i]].insert(pbit);
 | 
				
			||||||
					cell_outputs[cell].insert(bits[i]);
 | 
										cell_outputs[cell].insert(bits[i]);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,7 +36,7 @@ YOSYS_NAMESPACE_BEGIN
 | 
				
			||||||
bool RTLIL::IdString::destruct_guard_ok = false;
 | 
					bool RTLIL::IdString::destruct_guard_ok = false;
 | 
				
			||||||
RTLIL::IdString::destruct_guard_t RTLIL::IdString::destruct_guard;
 | 
					RTLIL::IdString::destruct_guard_t RTLIL::IdString::destruct_guard;
 | 
				
			||||||
std::vector<char*> RTLIL::IdString::global_id_storage_;
 | 
					std::vector<char*> RTLIL::IdString::global_id_storage_;
 | 
				
			||||||
dict<char*, int, hash_cstr_ops> RTLIL::IdString::global_id_index_;
 | 
					dict<char*, int> RTLIL::IdString::global_id_index_;
 | 
				
			||||||
#ifndef YOSYS_NO_IDS_REFCNT
 | 
					#ifndef YOSYS_NO_IDS_REFCNT
 | 
				
			||||||
std::vector<int> RTLIL::IdString::global_refcount_storage_;
 | 
					std::vector<int> RTLIL::IdString::global_refcount_storage_;
 | 
				
			||||||
std::vector<int> RTLIL::IdString::global_free_idx_list_;
 | 
					std::vector<int> RTLIL::IdString::global_free_idx_list_;
 | 
				
			||||||
| 
						 | 
					@ -4492,17 +4492,17 @@ void RTLIL::SigSpec::updhash() const
 | 
				
			||||||
	cover("kernel.rtlil.sigspec.hash");
 | 
						cover("kernel.rtlil.sigspec.hash");
 | 
				
			||||||
	that->pack();
 | 
						that->pack();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	that->hash_ = mkhash_init;
 | 
						Hasher h;
 | 
				
			||||||
	for (auto &c : that->chunks_)
 | 
						for (auto &c : that->chunks_)
 | 
				
			||||||
		if (c.wire == NULL) {
 | 
							if (c.wire == NULL) {
 | 
				
			||||||
			for (auto &v : c.data)
 | 
								for (auto &v : c.data)
 | 
				
			||||||
				that->hash_ = mkhash(that->hash_, v);
 | 
									h.eat(v);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			that->hash_ = mkhash(that->hash_, c.wire->name.index_);
 | 
								h.eat(c.wire->name.index_);
 | 
				
			||||||
			that->hash_ = mkhash(that->hash_, c.offset);
 | 
								h.eat(c.offset);
 | 
				
			||||||
			that->hash_ = mkhash(that->hash_, c.width);
 | 
								h.eat(c.width);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						that->hash_ = h.yield();
 | 
				
			||||||
	if (that->hash_ == 0)
 | 
						if (that->hash_ == 0)
 | 
				
			||||||
		that->hash_ = 1;
 | 
							that->hash_ = 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										685
									
								
								kernel/rtlil.h
									
										
									
									
									
								
							
							
						
						
									
										685
									
								
								kernel/rtlil.h
									
										
									
									
									
								
							| 
						 | 
					@ -76,329 +76,354 @@ namespace RTLIL
 | 
				
			||||||
	struct SyncRule;
 | 
						struct SyncRule;
 | 
				
			||||||
	struct Process;
 | 
						struct Process;
 | 
				
			||||||
	struct Binding;
 | 
						struct Binding;
 | 
				
			||||||
 | 
						struct IdString;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	typedef std::pair<SigSpec, SigSpec> SigSig;
 | 
						typedef std::pair<SigSpec, SigSpec> 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<char*> global_id_storage_;
 | 
				
			||||||
 | 
						static dict<char*, int> global_id_index_;
 | 
				
			||||||
 | 
					#ifndef YOSYS_NO_IDS_REFCNT
 | 
				
			||||||
 | 
						static std::vector<int> global_refcount_storage_;
 | 
				
			||||||
 | 
						static std::vector<int> 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
 | 
						#ifdef YOSYS_XTRACE_GET_PUT
 | 
				
			||||||
		#undef YOSYS_SORT_ID_FREE_LIST
 | 
							for (int idx = 0; idx < GetSize(global_id_storage_); idx++)
 | 
				
			||||||
		#undef YOSYS_USE_STICKY_IDS
 | 
							{
 | 
				
			||||||
		#undef YOSYS_NO_IDS_REFCNT
 | 
								if (global_id_storage_.at(idx) == nullptr)
 | 
				
			||||||
 | 
									log("#X# DB-DUMP index %d: FREE\n", idx);
 | 
				
			||||||
		// the global id string cache
 | 
								else
 | 
				
			||||||
 | 
									log("#X# DB-DUMP index %d: '%s' (ref %d)\n", idx, global_id_storage_.at(idx), global_refcount_storage_.at(idx));
 | 
				
			||||||
		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<char*> global_id_storage_;
 | 
					 | 
				
			||||||
		static dict<char*, int, hash_cstr_ops> global_id_index_;
 | 
					 | 
				
			||||||
	#ifndef YOSYS_NO_IDS_REFCNT
 | 
					 | 
				
			||||||
		static std::vector<int> global_refcount_storage_;
 | 
					 | 
				
			||||||
		static std::vector<int> global_free_idx_list_;
 | 
					 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static inline void checkpoint()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
	#ifdef YOSYS_USE_STICKY_IDS
 | 
						#ifdef YOSYS_USE_STICKY_IDS
 | 
				
			||||||
		static int last_created_idx_ptr_;
 | 
							last_created_idx_ptr_ = 0;
 | 
				
			||||||
		static int last_created_idx_[8];
 | 
							for (int i = 0; i < 8; i++) {
 | 
				
			||||||
 | 
								if (last_created_idx_[i])
 | 
				
			||||||
 | 
									put_reference(last_created_idx_[i]);
 | 
				
			||||||
 | 
								last_created_idx_[i] = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
 | 
						#ifdef YOSYS_SORT_ID_FREE_LIST
 | 
				
			||||||
 | 
							std::sort(global_free_idx_list_.begin(), global_free_idx_list_.end(), std::greater<int>());
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		static inline void xtrace_db_dump()
 | 
						static inline int get_reference(int idx)
 | 
				
			||||||
		{
 | 
						{
 | 
				
			||||||
		#ifdef YOSYS_XTRACE_GET_PUT
 | 
							if (idx) {
 | 
				
			||||||
			for (int idx = 0; idx < GetSize(global_id_storage_); idx++)
 | 
						#ifndef YOSYS_NO_IDS_REFCNT
 | 
				
			||||||
			{
 | 
								global_refcount_storage_[idx]++;
 | 
				
			||||||
				if (global_id_storage_.at(idx) == nullptr)
 | 
						#endif
 | 
				
			||||||
					log("#X# DB-DUMP index %d: FREE\n", idx);
 | 
						#ifdef YOSYS_XTRACE_GET_PUT
 | 
				
			||||||
				else
 | 
								if (yosys_xtrace)
 | 
				
			||||||
					log("#X# DB-DUMP index %d: '%s' (ref %d)\n", idx, global_id_storage_.at(idx), global_refcount_storage_.at(idx));
 | 
									log("#X# GET-BY-INDEX '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
 | 
				
			||||||
			}
 | 
						#endif
 | 
				
			||||||
		#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()
 | 
							log_assert(p[0] == '$' || p[0] == '\\');
 | 
				
			||||||
		{
 | 
							log_assert(p[1] != 0);
 | 
				
			||||||
		#ifdef YOSYS_USE_STICKY_IDS
 | 
							for (const char *c = p; *c; c++)
 | 
				
			||||||
			last_created_idx_ptr_ = 0;
 | 
								if ((unsigned)*c <= (unsigned)' ')
 | 
				
			||||||
			for (int i = 0; i < 8; i++) {
 | 
									log_error("Found control character or space (0x%02x) in string '%s' which is not allowed in RTLIL identifiers\n", *c, p);
 | 
				
			||||||
				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<int>());
 | 
					 | 
				
			||||||
		#endif
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		static inline int get_reference(int idx)
 | 
						#ifndef YOSYS_NO_IDS_REFCNT
 | 
				
			||||||
		{
 | 
							if (global_free_idx_list_.empty()) {
 | 
				
			||||||
			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
 | 
					 | 
				
			||||||
			if (global_id_storage_.empty()) {
 | 
								if (global_id_storage_.empty()) {
 | 
				
			||||||
 | 
									global_refcount_storage_.push_back(0);
 | 
				
			||||||
				global_id_storage_.push_back((char*)"");
 | 
									global_id_storage_.push_back((char*)"");
 | 
				
			||||||
				global_id_index_[global_id_storage_.back()] = 0;
 | 
									global_id_index_[global_id_storage_.back()] = 0;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			int idx = global_id_storage_.size();
 | 
								log_assert(global_id_storage_.size() < 0x40000000);
 | 
				
			||||||
			global_id_storage_.push_back(strdup(p));
 | 
								global_free_idx_list_.push_back(global_id_storage_.size());
 | 
				
			||||||
			global_id_index_[global_id_storage_.back()] = idx;
 | 
								global_id_storage_.push_back(nullptr);
 | 
				
			||||||
		#endif
 | 
								global_refcount_storage_.push_back(0);
 | 
				
			||||||
 | 
					 | 
				
			||||||
			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;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	#ifndef YOSYS_NO_IDS_REFCNT
 | 
							int idx = global_free_idx_list_.back();
 | 
				
			||||||
		static inline void put_reference(int idx)
 | 
							global_free_idx_list_.pop_back();
 | 
				
			||||||
		{
 | 
							global_id_storage_.at(idx) = strdup(p);
 | 
				
			||||||
			// put_reference() may be called from destructors after the destructor of
 | 
							global_id_index_[global_id_storage_.at(idx)] = idx;
 | 
				
			||||||
			// global_refcount_storage_ has been run. in this case we simply do nothing.
 | 
							global_refcount_storage_.at(idx)++;
 | 
				
			||||||
			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);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	#else
 | 
						#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
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// the actual IdString object is just is a single int
 | 
							if (yosys_xtrace) {
 | 
				
			||||||
 | 
								log("#X# New IdString '%s' with index %d.\n", p, idx);
 | 
				
			||||||
		int index_;
 | 
								log_backtrace("-X- ", yosys_xtrace-1);
 | 
				
			||||||
 | 
					 | 
				
			||||||
		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) {
 | 
						#ifdef YOSYS_XTRACE_GET_PUT
 | 
				
			||||||
			IdString id(rhs);
 | 
							if (yosys_xtrace)
 | 
				
			||||||
			*this = id;
 | 
								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) {
 | 
							global_id_index_.erase(global_id_storage_.at(idx));
 | 
				
			||||||
			IdString id(rhs);
 | 
							free(global_id_storage_.at(idx));
 | 
				
			||||||
			*this = id;
 | 
							global_id_storage_.at(idx) = nullptr;
 | 
				
			||||||
		}
 | 
							global_free_idx_list_.push_back(idx);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
		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
 | 
					#else
 | 
				
			||||||
			return *(p + i);
 | 
						static inline void put_reference(int) { }
 | 
				
			||||||
#endif
 | 
					#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_into(Hasher h) const { return hash_ops<int>::hash_into(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<Cell*>
 | 
				
			||||||
 | 
						// use std::set<Cell*, IdString::compare_ptr_by_name<Cell>> if the order of cells in the
 | 
				
			||||||
 | 
						// set has an influence on the algorithm.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template<typename T> 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();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		unsigned int hash() const {
 | 
					 | 
				
			||||||
			return index_;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// The following is a helper key_compare class. Instead of for example std::set<Cell*>
 | 
					 | 
				
			||||||
		// use std::set<Cell*, IdString::compare_ptr_by_name<Cell>> if the order of cells in the
 | 
					 | 
				
			||||||
		// set has an influence on the algorithm.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		template<typename T> 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<typename... Args>
 | 
					 | 
				
			||||||
		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<int>{ (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<IdString> &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<typename... Args>
 | 
				
			||||||
 | 
						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<IdString> &rhs) const;
 | 
				
			||||||
 | 
						inline bool in(const pool<IdString> &&rhs) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool isPublic() const { return begins_with("\\"); }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace hashlib {
 | 
				
			||||||
 | 
						template <>
 | 
				
			||||||
 | 
						struct hash_top_ops<RTLIL::IdString> {
 | 
				
			||||||
 | 
							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();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * How to not use these methods:
 | 
				
			||||||
 | 
					 * 1. if(celltype.in({...})) -> if(celltype.in(...))
 | 
				
			||||||
 | 
					 * 2. pool<IdString> p; ... a.in(p) -> (bool)p.count(a)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					[[deprecated]]
 | 
				
			||||||
 | 
					inline bool RTLIL::IdString::in(const pool<IdString> &rhs) const { return rhs.count(*this) != 0; }
 | 
				
			||||||
 | 
					[[deprecated]]
 | 
				
			||||||
 | 
					inline bool RTLIL::IdString::in(const pool<IdString> &&rhs) const { return rhs.count(*this) != 0; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace RTLIL {
 | 
				
			||||||
	namespace ID {
 | 
						namespace ID {
 | 
				
			||||||
#define X(_id) extern IdString _id;
 | 
					#define X(_id) extern IdString _id;
 | 
				
			||||||
#include "kernel/constids.inc"
 | 
					#include "kernel/constids.inc"
 | 
				
			||||||
#undef X
 | 
					#undef X
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					 | 
				
			||||||
	extern dict<std::string, std::string> constpad;
 | 
						extern dict<std::string, std::string> constpad;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const pool<IdString> &builtin_ff_cell_types();
 | 
						const pool<IdString> &builtin_ff_cell_types();
 | 
				
			||||||
| 
						 | 
					@ -802,11 +827,10 @@ public:
 | 
				
			||||||
		bv.resize(width, bv.empty() ? RTLIL::State::Sx : bv.back());
 | 
							bv.resize(width, bv.empty() ? RTLIL::State::Sx : bv.back());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inline unsigned int hash() const {
 | 
						inline Hasher hash_into(Hasher h) const {
 | 
				
			||||||
		unsigned int h = mkhash_init;
 | 
							h.eat(size());
 | 
				
			||||||
 | 
							for (auto b : *this)
 | 
				
			||||||
		for (State b : *this)
 | 
								h.eat(b);
 | 
				
			||||||
			h = mkhash(h, b);
 | 
					 | 
				
			||||||
		return h;
 | 
							return h;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -896,7 +920,20 @@ struct RTLIL::SigBit
 | 
				
			||||||
	bool operator <(const RTLIL::SigBit &other) const;
 | 
						bool operator <(const RTLIL::SigBit &other) const;
 | 
				
			||||||
	bool operator ==(const RTLIL::SigBit &other) const;
 | 
						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_into(Hasher h) const;
 | 
				
			||||||
 | 
						Hasher hash_top() const;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace hashlib {
 | 
				
			||||||
 | 
						template <>
 | 
				
			||||||
 | 
						struct hash_top_ops<RTLIL::SigBit> {
 | 
				
			||||||
 | 
							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
 | 
					struct RTLIL::SigSpecIterator
 | 
				
			||||||
| 
						 | 
					@ -937,7 +974,7 @@ struct RTLIL::SigSpec
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	int width_;
 | 
						int width_;
 | 
				
			||||||
	unsigned long hash_;
 | 
						Hasher::hash_t hash_;
 | 
				
			||||||
	std::vector<RTLIL::SigChunk> chunks_; // LSB at index 0
 | 
						std::vector<RTLIL::SigChunk> chunks_; // LSB at index 0
 | 
				
			||||||
	std::vector<RTLIL::SigBit> bits_; // LSB at index 0
 | 
						std::vector<RTLIL::SigBit> bits_; // LSB at index 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -978,11 +1015,6 @@ public:
 | 
				
			||||||
	SigSpec(const std::set<RTLIL::SigBit> &bits);
 | 
						SigSpec(const std::set<RTLIL::SigBit> &bits);
 | 
				
			||||||
	explicit SigSpec(bool bit);
 | 
						explicit SigSpec(bool bit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	size_t get_hash() const {
 | 
					 | 
				
			||||||
		if (!hash_) hash();
 | 
					 | 
				
			||||||
		return hash_;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	inline const std::vector<RTLIL::SigChunk> &chunks() const { pack(); return chunks_; }
 | 
						inline const std::vector<RTLIL::SigChunk> &chunks() const { pack(); return chunks_; }
 | 
				
			||||||
	inline const std::vector<RTLIL::SigBit> &bits() const { inline_unpack(); return bits_; }
 | 
						inline const std::vector<RTLIL::SigBit> &bits() const { inline_unpack(); return bits_; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1089,7 +1121,7 @@ public:
 | 
				
			||||||
	operator std::vector<RTLIL::SigBit>() const { return bits(); }
 | 
						operator std::vector<RTLIL::SigBit>() const { return bits(); }
 | 
				
			||||||
	const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; }
 | 
						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_into(Hasher h) const { if (!hash_) updhash(); h.eat(hash_); return h; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef NDEBUG
 | 
					#ifndef NDEBUG
 | 
				
			||||||
	void check(Module *mod = nullptr) const;
 | 
						void check(Module *mod = nullptr) const;
 | 
				
			||||||
| 
						 | 
					@ -1130,8 +1162,8 @@ struct RTLIL::Selection
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct RTLIL::Monitor
 | 
					struct RTLIL::Monitor
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int hashidx_;
 | 
						Hasher::hash_t hashidx_;
 | 
				
			||||||
	unsigned int hash() const { return hashidx_; }
 | 
						Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Monitor() {
 | 
						Monitor() {
 | 
				
			||||||
		static unsigned int hashidx_count = 123456789;
 | 
							static unsigned int hashidx_count = 123456789;
 | 
				
			||||||
| 
						 | 
					@ -1153,8 +1185,8 @@ struct define_map_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct RTLIL::Design
 | 
					struct RTLIL::Design
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int hashidx_;
 | 
						Hasher::hash_t hashidx_;
 | 
				
			||||||
	unsigned int hash() const { return hashidx_; }
 | 
						Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pool<RTLIL::Monitor*> monitors;
 | 
						pool<RTLIL::Monitor*> monitors;
 | 
				
			||||||
	dict<std::string, std::string> scratchpad;
 | 
						dict<std::string, std::string> scratchpad;
 | 
				
			||||||
| 
						 | 
					@ -1258,8 +1290,8 @@ struct RTLIL::Design
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct RTLIL::Module : public RTLIL::AttrObject
 | 
					struct RTLIL::Module : public RTLIL::AttrObject
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int hashidx_;
 | 
						Hasher::hash_t hashidx_;
 | 
				
			||||||
	unsigned int hash() const { return hashidx_; }
 | 
						Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	void add(RTLIL::Wire *wire);
 | 
						void add(RTLIL::Wire *wire);
 | 
				
			||||||
| 
						 | 
					@ -1616,8 +1648,8 @@ void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct RTLIL::Wire : public RTLIL::AttrObject
 | 
					struct RTLIL::Wire : public RTLIL::AttrObject
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int hashidx_;
 | 
						Hasher::hash_t hashidx_;
 | 
				
			||||||
	unsigned int hash() const { return hashidx_; }
 | 
						Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	// use module->addWire() and module->remove() to create or destroy wires
 | 
						// use module->addWire() and module->remove() to create or destroy wires
 | 
				
			||||||
| 
						 | 
					@ -1655,8 +1687,8 @@ inline int GetSize(RTLIL::Wire *wire) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct RTLIL::Memory : public RTLIL::AttrObject
 | 
					struct RTLIL::Memory : public RTLIL::AttrObject
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int hashidx_;
 | 
						Hasher::hash_t hashidx_;
 | 
				
			||||||
	unsigned int hash() const { return hashidx_; }
 | 
						Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Memory();
 | 
						Memory();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1670,8 +1702,8 @@ struct RTLIL::Memory : public RTLIL::AttrObject
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct RTLIL::Cell : public RTLIL::AttrObject
 | 
					struct RTLIL::Cell : public RTLIL::AttrObject
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int hashidx_;
 | 
						Hasher::hash_t hashidx_;
 | 
				
			||||||
	unsigned int hash() const { return hashidx_; }
 | 
						Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	// use module->addCell() and module->remove() to create or destroy cells
 | 
						// use module->addCell() and module->remove() to create or destroy cells
 | 
				
			||||||
| 
						 | 
					@ -1780,8 +1812,8 @@ struct RTLIL::SyncRule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct RTLIL::Process : public RTLIL::AttrObject
 | 
					struct RTLIL::Process : public RTLIL::AttrObject
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int hashidx_;
 | 
						Hasher::hash_t hashidx_;
 | 
				
			||||||
	unsigned int hash() const { return hashidx_; }
 | 
						Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	// use module->addProcess() and module->remove() to create or destroy processes
 | 
						// use module->addProcess() and module->remove() to create or destroy processes
 | 
				
			||||||
| 
						 | 
					@ -1825,10 +1857,25 @@ inline bool RTLIL::SigBit::operator!=(const RTLIL::SigBit &other) const {
 | 
				
			||||||
	return (wire != other.wire) || (wire ? (offset != other.offset) : (data != other.data));
 | 
						return (wire != other.wire) || (wire ? (offset != other.offset) : (data != other.data));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline unsigned int RTLIL::SigBit::hash() const {
 | 
					inline Hasher RTLIL::SigBit::hash_into(Hasher h) const {
 | 
				
			||||||
	if (wire)
 | 
						if (wire) {
 | 
				
			||||||
		return mkhash_add(wire->name.hash(), offset);
 | 
							h.eat(offset);
 | 
				
			||||||
	return data;
 | 
							h.eat(wire->name);
 | 
				
			||||||
 | 
							return h;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						h.eat(data);
 | 
				
			||||||
 | 
						return h;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline Hasher RTLIL::SigBit::hash_top() const {
 | 
				
			||||||
 | 
						Hasher h;
 | 
				
			||||||
 | 
						if (wire) {
 | 
				
			||||||
 | 
							h.force(hashlib::legacy::djb2_add(wire->name.index_, offset));
 | 
				
			||||||
 | 
							return h;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						h.force(data);
 | 
				
			||||||
 | 
						return h;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const {
 | 
					inline RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -169,8 +169,11 @@ public:
 | 
				
			||||||
			return !(*this == other);
 | 
								return !(*this == other);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		int hash() const {
 | 
							Hasher hash_into(Hasher h) const
 | 
				
			||||||
			return mkhash(scope_name.hash(), hash_ptr_ops::hash(target));
 | 
							{
 | 
				
			||||||
 | 
								h.eat(scope_name);
 | 
				
			||||||
 | 
								h.eat(target);
 | 
				
			||||||
 | 
								return h;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bool valid() const {
 | 
							bool valid() const {
 | 
				
			||||||
| 
						 | 
					@ -322,7 +325,7 @@ struct ModuleItem {
 | 
				
			||||||
	Cell *cell() const { return type == Type::Cell ? static_cast<Cell *>(ptr) : nullptr; }
 | 
						Cell *cell() const { return type == Type::Cell ? static_cast<Cell *>(ptr) : nullptr; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool operator==(const ModuleItem &other) const { return ptr == other.ptr && type == other.type; }
 | 
						bool operator==(const ModuleItem &other) const { return ptr == other.ptr && type == other.type; }
 | 
				
			||||||
	unsigned int hash() const { return (uintptr_t)ptr; }
 | 
						Hasher hash_into(Hasher h) const { h.eat(ptr); return h; }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void log_dump_val_worker(typename IdTree<ModuleItem>::Cursor cursor ) { log("%p %s", cursor.target, log_id(cursor.scope_name)); }
 | 
					static inline void log_dump_val_worker(typename IdTree<ModuleItem>::Cursor cursor ) { log("%p %s", cursor.target, log_id(cursor.scope_name)); }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,7 +29,11 @@ struct SigPool
 | 
				
			||||||
	struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
 | 
						struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
 | 
				
			||||||
		bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
 | 
							bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
 | 
				
			||||||
		bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
 | 
							bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
 | 
				
			||||||
		unsigned int hash() const { return first->name.hash() + second; }
 | 
							Hasher hash_into(Hasher h) const {
 | 
				
			||||||
 | 
								h.eat(first->name);
 | 
				
			||||||
 | 
								h.eat(second);
 | 
				
			||||||
 | 
								return h;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pool<bitDef_t> bits;
 | 
						pool<bitDef_t> bits;
 | 
				
			||||||
| 
						 | 
					@ -143,7 +147,11 @@ struct SigSet
 | 
				
			||||||
	struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
 | 
						struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
 | 
				
			||||||
		bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
 | 
							bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
 | 
				
			||||||
		bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
 | 
							bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
 | 
				
			||||||
		unsigned int hash() const { return first->name.hash() + second; }
 | 
							Hasher hash_into(Hasher h) const {
 | 
				
			||||||
 | 
								h.eat(first->name);
 | 
				
			||||||
 | 
								h.eat(second);
 | 
				
			||||||
 | 
								return h;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dict<bitDef_t, std::set<T, Compare>> bits;
 | 
						dict<bitDef_t, std::set<T, Compare>> bits;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,7 +36,6 @@ struct TimingInfo
 | 
				
			||||||
		explicit NameBit(const RTLIL::SigBit &b) : name(b.wire->name), offset(b.offset) {}
 | 
							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 nb.name == name && nb.offset == offset; }
 | 
				
			||||||
		bool operator!=(const NameBit& nb) const { return !operator==(nb); }
 | 
							bool operator!=(const NameBit& nb) const { return !operator==(nb); }
 | 
				
			||||||
		unsigned int hash() const { return mkhash_add(name.hash(), offset); }
 | 
					 | 
				
			||||||
		std::optional<SigBit> get_connection(RTLIL::Cell *cell) {
 | 
							std::optional<SigBit> get_connection(RTLIL::Cell *cell) {
 | 
				
			||||||
			if (!cell->hasPort(name))
 | 
								if (!cell->hasPort(name))
 | 
				
			||||||
				return {};
 | 
									return {};
 | 
				
			||||||
| 
						 | 
					@ -45,6 +44,11 @@ struct TimingInfo
 | 
				
			||||||
				return {};
 | 
									return {};
 | 
				
			||||||
			return port[offset];
 | 
								return port[offset];
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							Hasher hash_into(Hasher h) const {
 | 
				
			||||||
 | 
								h.eat(name);
 | 
				
			||||||
 | 
								h.eat(offset);
 | 
				
			||||||
 | 
								return h;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	struct BitBit
 | 
						struct BitBit
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
| 
						 | 
					@ -52,7 +56,11 @@ struct TimingInfo
 | 
				
			||||||
		BitBit(const NameBit &first, const NameBit &second) : first(first), second(second) {}
 | 
							BitBit(const NameBit &first, const NameBit &second) : first(first), second(second) {}
 | 
				
			||||||
		BitBit(const SigBit &first, const SigBit &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; }
 | 
							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_into(Hasher h) const {
 | 
				
			||||||
 | 
								h.eat(first);
 | 
				
			||||||
 | 
								h.eat(second);
 | 
				
			||||||
 | 
								return h;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct ModuleTiming
 | 
						struct ModuleTiming
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,17 +31,17 @@ YOSYS_NAMESPACE_BEGIN
 | 
				
			||||||
// A map-like container, but you can save and restore the state
 | 
					// A map-like container, but you can save and restore the state
 | 
				
			||||||
// ------------------------------------------------
 | 
					// ------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename Key, typename T, typename OPS = hash_ops<Key>>
 | 
					template<typename Key, typename T>
 | 
				
			||||||
struct stackmap
 | 
					struct stackmap
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	std::vector<dict<Key, T*, OPS>> backup_state;
 | 
						std::vector<dict<Key, T*>> backup_state;
 | 
				
			||||||
	dict<Key, T, OPS> current_state;
 | 
						dict<Key, T> current_state;
 | 
				
			||||||
	static T empty_tuple;
 | 
						static T empty_tuple;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	stackmap() { }
 | 
						stackmap() { }
 | 
				
			||||||
	stackmap(const dict<Key, T, OPS> &other) : current_state(other) { }
 | 
						stackmap(const dict<Key, T> &other) : current_state(other) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	template<typename Other>
 | 
						template<typename Other>
 | 
				
			||||||
	void operator=(const Other &other)
 | 
						void operator=(const Other &other)
 | 
				
			||||||
| 
						 | 
					@ -94,7 +94,7 @@ public:
 | 
				
			||||||
		current_state.erase(k);
 | 
							current_state.erase(k);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const dict<Key, T, OPS> &stdmap()
 | 
						const dict<Key, T> &stdmap()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return current_state;
 | 
							return current_state;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -128,7 +128,7 @@ public:
 | 
				
			||||||
// A simple class for topological sorting
 | 
					// A simple class for topological sorting
 | 
				
			||||||
// ------------------------------------------------
 | 
					// ------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename T, typename C = std::less<T>, typename OPS = hash_ops<T>> class TopoSort
 | 
					template <typename T, typename C = std::less<T>> class TopoSort
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
      public:
 | 
					      public:
 | 
				
			||||||
	// We use this ordering of the edges in the adjacency matrix for
 | 
						// We use this ordering of the edges in the adjacency matrix for
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -96,6 +96,7 @@ std::set<std::string> yosys_input_files, yosys_output_files;
 | 
				
			||||||
bool memhasher_active = false;
 | 
					bool memhasher_active = false;
 | 
				
			||||||
uint32_t memhasher_rng = 123456;
 | 
					uint32_t memhasher_rng = 123456;
 | 
				
			||||||
std::vector<void*> memhasher_store;
 | 
					std::vector<void*> memhasher_store;
 | 
				
			||||||
 | 
					uint32_t Hasher::fudge = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string yosys_share_dirname;
 | 
					std::string yosys_share_dirname;
 | 
				
			||||||
std::string yosys_abc_executable;
 | 
					std::string yosys_abc_executable;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -134,8 +134,7 @@ YOSYS_NAMESPACE_BEGIN
 | 
				
			||||||
// Note: All headers included in hashlib.h must be included
 | 
					// Note: All headers included in hashlib.h must be included
 | 
				
			||||||
// outside of YOSYS_NAMESPACE before this or bad things will happen.
 | 
					// outside of YOSYS_NAMESPACE before this or bad things will happen.
 | 
				
			||||||
#ifdef HASHLIB_H
 | 
					#ifdef HASHLIB_H
 | 
				
			||||||
#  undef HASHLIB_H
 | 
					#  error "You've probably included hashlib.h under two namespace paths. Bad idea."
 | 
				
			||||||
#  include "kernel/hashlib.h"
 | 
					 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#  include "kernel/hashlib.h"
 | 
					#  include "kernel/hashlib.h"
 | 
				
			||||||
#  undef HASHLIB_H
 | 
					#  undef HASHLIB_H
 | 
				
			||||||
| 
						 | 
					@ -153,6 +152,15 @@ using std::get;
 | 
				
			||||||
using std::min;
 | 
					using std::min;
 | 
				
			||||||
using std::max;
 | 
					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
 | 
					// A primitive shared string implementation that does not
 | 
				
			||||||
// move its .c_str() when the object is copied or moved.
 | 
					// move its .c_str() when the object is copied or moved.
 | 
				
			||||||
struct shared_str {
 | 
					struct shared_str {
 | 
				
			||||||
| 
						 | 
					@ -163,22 +171,12 @@ struct shared_str {
 | 
				
			||||||
	const char *c_str() const { return content->c_str(); }
 | 
						const char *c_str() const { return content->c_str(); }
 | 
				
			||||||
	const string &str() const { return *content; }
 | 
						const string &str() const { return *content; }
 | 
				
			||||||
	bool operator==(const shared_str &other) const { return *content == *other.content; }
 | 
						bool operator==(const shared_str &other) const { return *content == *other.content; }
 | 
				
			||||||
	unsigned int hash() const { return hashlib::hash_ops<std::string>::hash(*content); }
 | 
						Hasher hash_into(Hasher h) const {
 | 
				
			||||||
 | 
							h.eat(*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 {
 | 
					namespace RTLIL {
 | 
				
			||||||
	struct IdString;
 | 
						struct IdString;
 | 
				
			||||||
	struct Const;
 | 
						struct Const;
 | 
				
			||||||
| 
						 | 
					@ -357,10 +355,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; })()
 | 
					        static const YOSYS_NAMESPACE_PREFIX RTLIL::IdString id(q); return id; })()
 | 
				
			||||||
namespace ID = RTLIL::ID;
 | 
					namespace ID = RTLIL::ID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace hashlib {
 | 
					 | 
				
			||||||
	template<> struct hash_ops<RTLIL::State> : hash_ops<int> {};
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
YOSYS_NAMESPACE_END
 | 
					YOSYS_NAMESPACE_END
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,7 +35,10 @@ struct IdPath : public std::vector<RTLIL::IdString>
 | 
				
			||||||
	bool has_address() const { int tmp; return get_address(tmp); };
 | 
						bool has_address() const { int tmp; return get_address(tmp); };
 | 
				
			||||||
	bool get_address(int &addr) const;
 | 
						bool get_address(int &addr) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int hash() const { return hashlib::hash_ops<std::vector<RTLIL::IdString>>::hash(*this); }
 | 
						Hasher hash_into(Hasher h) const {
 | 
				
			||||||
 | 
							h.eat(static_cast<const std::vector<RTLIL::IdString>&&>(*this));
 | 
				
			||||||
 | 
							return h;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct WitnessHierarchyItem {
 | 
					struct WitnessHierarchyItem {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -855,7 +855,11 @@ class WClass:
 | 
				
			||||||
		if self.hash_id != None:
 | 
							if self.hash_id != None:
 | 
				
			||||||
			text += "\n\t\tunsigned int get_hash_py()"
 | 
								text += "\n\t\tunsigned int get_hash_py()"
 | 
				
			||||||
			text += "\n\t\t{"
 | 
								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\t}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		text += "\n\t};\n"
 | 
							text += "\n\t};\n"
 | 
				
			||||||
| 
						 | 
					@ -956,7 +960,7 @@ class WClass:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sources = [
 | 
					sources = [
 | 
				
			||||||
	Source("kernel/celltypes",[
 | 
						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)
 | 
							WClass("CellTypes", link_types.pointer, None, None, None, True)
 | 
				
			||||||
		]
 | 
							]
 | 
				
			||||||
		),
 | 
							),
 | 
				
			||||||
| 
						 | 
					@ -970,23 +974,23 @@ sources = [
 | 
				
			||||||
		]
 | 
							]
 | 
				
			||||||
		),
 | 
							),
 | 
				
			||||||
	Source("kernel/rtlil",[
 | 
						Source("kernel/rtlil",[
 | 
				
			||||||
		WClass("IdString", link_types.ref_copy, None, "str()", "hash()"),
 | 
							WClass("IdString", link_types.ref_copy, None, "str()", ""),
 | 
				
			||||||
		WClass("Const", link_types.ref_copy, None, "as_string()", "hash()"),
 | 
							WClass("Const", link_types.ref_copy, None, "as_string()", ""),
 | 
				
			||||||
		WClass("AttrObject", link_types.ref_copy, None, None, None),
 | 
							WClass("AttrObject", link_types.ref_copy, None, None, None),
 | 
				
			||||||
		WClass("Selection", 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("Monitor", link_types.derive, None, None, None),
 | 
				
			||||||
		WClass("CaseRule",link_types.ref_copy, None, None, None, True),
 | 
							WClass("CaseRule",link_types.ref_copy, None, None, None, True),
 | 
				
			||||||
		WClass("SwitchRule",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("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("SigChunk", link_types.ref_copy, None, None, None),
 | 
				
			||||||
		WClass("SigBit", link_types.ref_copy, None, None, "hash()"),
 | 
							WClass("SigBit", link_types.ref_copy, None, None, ""),
 | 
				
			||||||
		WClass("SigSpec", link_types.ref_copy, None, None, "hash()"),
 | 
							WClass("SigSpec", link_types.ref_copy, None, None, ""),
 | 
				
			||||||
		WClass("Cell", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"),
 | 
							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()", "hash()"),
 | 
							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()", "hash()"),
 | 
							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()", "hash()"),
 | 
							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_", "hash()")
 | 
							WClass("Design", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "hashidx_", "")
 | 
				
			||||||
		]
 | 
							]
 | 
				
			||||||
		),
 | 
							),
 | 
				
			||||||
	#Source("kernel/satgen",[
 | 
						#Source("kernel/satgen",[
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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; }
 | 
				
			||||||
		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<int>::hash(index); }
 | 
							Hasher hash_into(Hasher h) const { h.eat(index); return h; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bool empty() const { return index == 0; }
 | 
							bool empty() const { return index == 0; }
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -52,8 +52,10 @@ struct ExampleDtPass : public Pass
 | 
				
			||||||
					return name == other.name && parameters == other.parameters;
 | 
										return name == other.name && parameters == other.parameters;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				unsigned int hash() const {
 | 
									Hasher hash_into(Hasher h) const {
 | 
				
			||||||
					return mkhash(name.hash(), parameters.hash());
 | 
										h.eat(name);
 | 
				
			||||||
 | 
										h.eat(parameters);
 | 
				
			||||||
 | 
										return h;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			};
 | 
								};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,7 +20,6 @@
 | 
				
			||||||
#include "kernel/register.h"
 | 
					#include "kernel/register.h"
 | 
				
			||||||
#include "kernel/rtlil.h"
 | 
					#include "kernel/rtlil.h"
 | 
				
			||||||
#include "kernel/log.h"
 | 
					#include "kernel/log.h"
 | 
				
			||||||
#include "kernel/hashlib.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
USING_YOSYS_NAMESPACE
 | 
					USING_YOSYS_NAMESPACE
 | 
				
			||||||
PRIVATE_NAMESPACE_BEGIN
 | 
					PRIVATE_NAMESPACE_BEGIN
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,13 +70,13 @@ struct GraphNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pool<IdString> names_;
 | 
						pool<IdString> names_;
 | 
				
			||||||
	dict<int, uint8_t> tags_;
 | 
						dict<int, uint8_t> tags_;
 | 
				
			||||||
	pool<GraphNode*, hash_ptr_ops> upstream_;
 | 
						pool<GraphNode*> upstream_;
 | 
				
			||||||
	pool<GraphNode*, hash_ptr_ops> downstream_;
 | 
						pool<GraphNode*> downstream_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pool<IdString> &names() { return get()->names_; }
 | 
						pool<IdString> &names() { return get()->names_; }
 | 
				
			||||||
	dict<int, uint8_t> &tags() { return get()->tags_; }
 | 
						dict<int, uint8_t> &tags() { return get()->tags_; }
 | 
				
			||||||
	pool<GraphNode*, hash_ptr_ops> &upstream() { return get()->upstream_; }
 | 
						pool<GraphNode*> &upstream() { return get()->upstream_; }
 | 
				
			||||||
	pool<GraphNode*, hash_ptr_ops> &downstream() { return get()->downstream_; }
 | 
						pool<GraphNode*> &downstream() { return get()->downstream_; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint8_t tag(int index) {
 | 
						uint8_t tag(int index) {
 | 
				
			||||||
		return tags().at(index, 0);
 | 
							return tags().at(index, 0);
 | 
				
			||||||
| 
						 | 
					@ -154,8 +154,8 @@ struct Graph {
 | 
				
			||||||
			nodes.push_back(n);
 | 
								nodes.push_back(n);
 | 
				
			||||||
			n->index = GetSize(nodes);
 | 
								n->index = GetSize(nodes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			pool<GraphNode*, hash_ptr_ops> new_upstream;
 | 
								pool<GraphNode*> new_upstream;
 | 
				
			||||||
			pool<GraphNode*, hash_ptr_ops> new_downstream;
 | 
								pool<GraphNode*> new_downstream;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			for (auto g : n->upstream()) {
 | 
								for (auto g : n->upstream()) {
 | 
				
			||||||
				if (n != (g = g->get()))
 | 
									if (n != (g = g->get()))
 | 
				
			||||||
| 
						 | 
					@ -302,7 +302,7 @@ struct Graph {
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		pool<GraphNode*, hash_ptr_ops> excluded;
 | 
							pool<GraphNode*> excluded;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (auto grp : config.groups)
 | 
							for (auto grp : config.groups)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
| 
						 | 
					@ -348,7 +348,7 @@ struct Graph {
 | 
				
			||||||
			excluded.insert(g->get());
 | 
								excluded.insert(g->get());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		dict<Cell*, GraphNode*> cell_nodes;
 | 
							dict<Cell*, GraphNode*> cell_nodes;
 | 
				
			||||||
		dict<SigBit, pool<GraphNode*, hash_ptr_ops>> sig_users;
 | 
							dict<SigBit, pool<GraphNode*>> sig_users;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (auto cell : module->selected_cells()) {
 | 
							for (auto cell : module->selected_cells()) {
 | 
				
			||||||
			auto g = new GraphNode;
 | 
								auto g = new GraphNode;
 | 
				
			||||||
| 
						 | 
					@ -483,8 +483,8 @@ struct Graph {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				header("Any nodes with identical connections");
 | 
									header("Any nodes with identical connections");
 | 
				
			||||||
				typedef pair<pool<GraphNode*, hash_ptr_ops>, pool<GraphNode*, hash_ptr_ops>> node_conn_t;
 | 
									typedef pair<pool<GraphNode*>, pool<GraphNode*>> node_conn_t;
 | 
				
			||||||
				dict<node_conn_t, pool<GraphNode*, hash_ptr_ops>> nodes_by_conn;
 | 
									dict<node_conn_t, pool<GraphNode*>> nodes_by_conn;
 | 
				
			||||||
				for (auto g : term ? term_nodes : nonterm_nodes) {
 | 
									for (auto g : term ? term_nodes : nonterm_nodes) {
 | 
				
			||||||
					auto &entry = nodes_by_conn[node_conn_t(g->upstream(), g->downstream())];
 | 
										auto &entry = nodes_by_conn[node_conn_t(g->upstream(), g->downstream())];
 | 
				
			||||||
					for (auto n : entry)
 | 
										for (auto n : entry)
 | 
				
			||||||
| 
						 | 
					@ -506,8 +506,8 @@ struct Graph {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				header("Sibblings with identical tags");
 | 
									header("Sibblings with identical tags");
 | 
				
			||||||
				for (auto g : nonterm_nodes) {
 | 
									for (auto g : nonterm_nodes) {
 | 
				
			||||||
					auto process_conns = [&](const pool<GraphNode*, hash_ptr_ops> &stream) {
 | 
										auto process_conns = [&](const pool<GraphNode*> &stream) {
 | 
				
			||||||
						dict<std::vector<int>, pool<GraphNode*, hash_ptr_ops>> nodes_by_tags;
 | 
											dict<std::vector<int>, pool<GraphNode*>> nodes_by_tags;
 | 
				
			||||||
						for (auto n : stream) {
 | 
											for (auto n : stream) {
 | 
				
			||||||
							if (n->terminal) continue;
 | 
												if (n->terminal) continue;
 | 
				
			||||||
							std::vector<int> key;
 | 
												std::vector<int> key;
 | 
				
			||||||
| 
						 | 
					@ -556,7 +556,7 @@ struct Graph {
 | 
				
			||||||
			if (!term) {
 | 
								if (!term) {
 | 
				
			||||||
				header("Sibblings with similar tags (strict)");
 | 
									header("Sibblings with similar tags (strict)");
 | 
				
			||||||
				for (auto g : nonterm_nodes) {
 | 
									for (auto g : nonterm_nodes) {
 | 
				
			||||||
					auto process_conns = [&](const pool<GraphNode*, hash_ptr_ops> &stream) {
 | 
										auto process_conns = [&](const pool<GraphNode*> &stream) {
 | 
				
			||||||
						std::vector<GraphNode*> nodes;
 | 
											std::vector<GraphNode*> nodes;
 | 
				
			||||||
						for (auto n : stream)
 | 
											for (auto n : stream)
 | 
				
			||||||
							if (!n->terminal) nodes.push_back(n);
 | 
												if (!n->terminal) nodes.push_back(n);
 | 
				
			||||||
| 
						 | 
					@ -585,7 +585,7 @@ struct Graph {
 | 
				
			||||||
			if (!term) {
 | 
								if (!term) {
 | 
				
			||||||
				header("Sibblings with similar tags (non-strict)");
 | 
									header("Sibblings with similar tags (non-strict)");
 | 
				
			||||||
				for (auto g : nonterm_nodes) {
 | 
									for (auto g : nonterm_nodes) {
 | 
				
			||||||
					auto process_conns = [&](const pool<GraphNode*, hash_ptr_ops> &stream) {
 | 
										auto process_conns = [&](const pool<GraphNode*> &stream) {
 | 
				
			||||||
						std::vector<GraphNode*> nodes;
 | 
											std::vector<GraphNode*> nodes;
 | 
				
			||||||
						for (auto n : stream)
 | 
											for (auto n : stream)
 | 
				
			||||||
							if (!n->terminal) nodes.push_back(n);
 | 
												if (!n->terminal) nodes.push_back(n);
 | 
				
			||||||
| 
						 | 
					@ -603,7 +603,7 @@ struct Graph {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				header("Any nodes with identical fan-in or fan-out");
 | 
									header("Any nodes with identical fan-in or fan-out");
 | 
				
			||||||
				dict<pool<GraphNode*, hash_ptr_ops>, pool<GraphNode*, hash_ptr_ops>> nodes_by_conn[2];
 | 
									dict<pool<GraphNode*>, pool<GraphNode*>> nodes_by_conn[2];
 | 
				
			||||||
				for (auto g : term ? term_nodes : nonterm_nodes) {
 | 
									for (auto g : term ? term_nodes : nonterm_nodes) {
 | 
				
			||||||
					auto &up_entry = nodes_by_conn[0][g->upstream()];
 | 
										auto &up_entry = nodes_by_conn[0][g->upstream()];
 | 
				
			||||||
					auto &down_entry = nodes_by_conn[1][g->downstream()];
 | 
										auto &down_entry = nodes_by_conn[1][g->downstream()];
 | 
				
			||||||
| 
						 | 
					@ -629,7 +629,7 @@ struct Graph {
 | 
				
			||||||
			if (!term) {
 | 
								if (!term) {
 | 
				
			||||||
				header("Sibblings with similar tags (lax)");
 | 
									header("Sibblings with similar tags (lax)");
 | 
				
			||||||
				for (auto g : nonterm_nodes) {
 | 
									for (auto g : nonterm_nodes) {
 | 
				
			||||||
					auto process_conns = [&](const pool<GraphNode*, hash_ptr_ops> &stream) {
 | 
										auto process_conns = [&](const pool<GraphNode*> &stream) {
 | 
				
			||||||
						std::vector<GraphNode*> nodes;
 | 
											std::vector<GraphNode*> nodes;
 | 
				
			||||||
						for (auto n : stream)
 | 
											for (auto n : stream)
 | 
				
			||||||
							if (!n->terminal) nodes.push_back(n);
 | 
												if (!n->terminal) nodes.push_back(n);
 | 
				
			||||||
| 
						 | 
					@ -720,9 +720,9 @@ struct VizWorker
 | 
				
			||||||
		fprintf(f, "digraph \"%s\" {\n", log_id(module));
 | 
							fprintf(f, "digraph \"%s\" {\n", log_id(module));
 | 
				
			||||||
		fprintf(f, "  rankdir = LR;\n");
 | 
							fprintf(f, "  rankdir = LR;\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		dict<GraphNode*, std::vector<std::vector<std::string>>, hash_ptr_ops> extra_lines;
 | 
							dict<GraphNode*, std::vector<std::vector<std::string>>> extra_lines;
 | 
				
			||||||
		dict<GraphNode*, GraphNode*, hash_ptr_ops> bypass_nodes;
 | 
							dict<GraphNode*, GraphNode*> bypass_nodes;
 | 
				
			||||||
		pool<GraphNode*, hash_ptr_ops> bypass_candidates;
 | 
							pool<GraphNode*> bypass_candidates;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto bypass = [&](GraphNode *g, GraphNode *n) {
 | 
							auto bypass = [&](GraphNode *g, GraphNode *n) {
 | 
				
			||||||
			log_assert(g->terminal);
 | 
								log_assert(g->terminal);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,11 +46,11 @@ struct EquivStructWorker
 | 
				
			||||||
					parameters == other.parameters && port_sizes == other.port_sizes;
 | 
										parameters == other.parameters && port_sizes == other.port_sizes;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		unsigned int hash() const {
 | 
							Hasher hash_into(Hasher h) const {
 | 
				
			||||||
			unsigned int h = mkhash_init;
 | 
								h.eat(type);
 | 
				
			||||||
			h = mkhash(h, mkhash(type));
 | 
								h.eat(parameters);
 | 
				
			||||||
			h = mkhash(h, mkhash(parameters));
 | 
								h.eat(port_sizes);
 | 
				
			||||||
			h = mkhash(h, mkhash(connections));
 | 
								h.eat(connections);
 | 
				
			||||||
			return h;
 | 
								return h;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -127,11 +127,10 @@ struct proc_dlatch_db_t
 | 
				
			||||||
			return signal == other.signal && match == other.match && children == other.children;
 | 
								return signal == other.signal && match == other.match && children == other.children;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		unsigned int hash() const {
 | 
							Hasher hash_into(Hasher h) const {
 | 
				
			||||||
			unsigned int h = mkhash_init;
 | 
								h.eat(signal);
 | 
				
			||||||
			mkhash(h, signal.hash());
 | 
								h.eat(match);
 | 
				
			||||||
			mkhash(h, match.hash());
 | 
								h.eat(children);
 | 
				
			||||||
			for (auto i : children) mkhash(h, i);
 | 
					 | 
				
			||||||
			return h;
 | 
								return h;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -108,8 +108,8 @@ struct SigSnippets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct SnippetSwCache
 | 
					struct SnippetSwCache
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	dict<RTLIL::SwitchRule*, pool<RTLIL::SigBit>, hash_ptr_ops> full_case_bits_cache;
 | 
						dict<RTLIL::SwitchRule*, pool<RTLIL::SigBit>> full_case_bits_cache;
 | 
				
			||||||
	dict<RTLIL::SwitchRule*, pool<int>, hash_ptr_ops> cache;
 | 
						dict<RTLIL::SwitchRule*, pool<int>> cache;
 | 
				
			||||||
	const SigSnippets *snippets;
 | 
						const SigSnippets *snippets;
 | 
				
			||||||
	int current_snippet;
 | 
						int current_snippet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -318,7 +318,7 @@ const pool<SigBit> &get_full_case_bits(SnippetSwCache &swcache, RTLIL::SwitchRul
 | 
				
			||||||
	return swcache.full_case_bits_cache.at(sw);
 | 
						return swcache.full_case_bits_cache.at(sw);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, dict<RTLIL::SwitchRule*, bool, hash_ptr_ops> &swpara,
 | 
					RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, dict<RTLIL::SwitchRule*, bool> &swpara,
 | 
				
			||||||
		RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval, bool ifxmode)
 | 
							RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval, bool ifxmode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	RTLIL::SigSpec result = defval;
 | 
						RTLIL::SigSpec result = defval;
 | 
				
			||||||
| 
						 | 
					@ -421,7 +421,7 @@ void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc, bool ifxmode)
 | 
				
			||||||
	swcache.snippets = &sigsnip;
 | 
						swcache.snippets = &sigsnip;
 | 
				
			||||||
	swcache.insert(&proc->root_case);
 | 
						swcache.insert(&proc->root_case);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dict<RTLIL::SwitchRule*, bool, hash_ptr_ops> swpara;
 | 
						dict<RTLIL::SwitchRule*, bool> swpara;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int cnt = 0;
 | 
						int cnt = 0;
 | 
				
			||||||
	for (int idx : sigsnip.snippets)
 | 
						for (int idx : sigsnip.snippets)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -176,7 +176,7 @@ struct coverdb_t
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mutate_queue_t
 | 
					struct mutate_queue_t
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	pool<mutate_t*, hash_ptr_ops> db;
 | 
						pool<mutate_t*> db;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) {
 | 
						mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) {
 | 
				
			||||||
		mutate_t *m = nullptr;
 | 
							mutate_t *m = nullptr;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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; };
 | 
				
			||||||
    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_into(Hasher h) const
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return mkhash_add(name.hash(), bit);
 | 
					        h.eat(name);
 | 
				
			||||||
 | 
					        h.eat(bit);
 | 
				
			||||||
 | 
					        return h;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    IdString name;
 | 
					    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; };
 | 
				
			||||||
    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_into(Hasher h) const
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return mkhash(bit.hash(), inverted);
 | 
					        h.eat(bit);
 | 
				
			||||||
 | 
					        h.eat(inverted);
 | 
				
			||||||
 | 
					        return h;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    IdBit bit;
 | 
					    IdBit bit;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -163,7 +163,7 @@ struct SimInstance
 | 
				
			||||||
	pool<SigBit> dirty_bits;
 | 
						pool<SigBit> dirty_bits;
 | 
				
			||||||
	pool<Cell*> dirty_cells;
 | 
						pool<Cell*> dirty_cells;
 | 
				
			||||||
	pool<IdString> dirty_memories;
 | 
						pool<IdString> dirty_memories;
 | 
				
			||||||
	pool<SimInstance*, hash_ptr_ops> dirty_children;
 | 
						pool<SimInstance*> dirty_children;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct ff_state_t
 | 
						struct ff_state_t
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1429,6 +1429,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
 | 
				
			||||||
			module->connect(conn);
 | 
								module->connect(conn);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							cell_stats.sort();
 | 
				
			||||||
		for (auto &it : cell_stats)
 | 
							for (auto &it : cell_stats)
 | 
				
			||||||
			log("ABC RESULTS:   %15s cells: %8d\n", it.first.c_str(), it.second);
 | 
								log("ABC RESULTS:   %15s cells: %8d\n", it.first.c_str(), it.second);
 | 
				
			||||||
		int in_wires = 0, out_wires = 0;
 | 
							int in_wires = 0, out_wires = 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -111,7 +111,7 @@ struct AlumaccWorker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dict<RTLIL::SigBit, int> bit_users;
 | 
						dict<RTLIL::SigBit, int> bit_users;
 | 
				
			||||||
	dict<RTLIL::SigSpec, maccnode_t*> sig_macc;
 | 
						dict<RTLIL::SigSpec, maccnode_t*> sig_macc;
 | 
				
			||||||
	dict<RTLIL::SigSig, pool<alunode_t*, hash_ptr_ops>> sig_alu;
 | 
						dict<RTLIL::SigSig, pool<alunode_t*>> sig_alu;
 | 
				
			||||||
	int macc_counter, alu_counter;
 | 
						int macc_counter, alu_counter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	AlumaccWorker(RTLIL::Module *module) : module(module), sigmap(module)
 | 
						AlumaccWorker(RTLIL::Module *module) : module(module), sigmap(module)
 | 
				
			||||||
| 
						 | 
					@ -226,7 +226,7 @@ struct AlumaccWorker
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		while (1)
 | 
							while (1)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			pool<maccnode_t*, hash_ptr_ops> delete_nodes;
 | 
								pool<maccnode_t*> delete_nodes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			for (auto &it : sig_macc)
 | 
								for (auto &it : sig_macc)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
| 
						 | 
					@ -278,7 +278,7 @@ struct AlumaccWorker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void macc_to_alu()
 | 
						void macc_to_alu()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		pool<maccnode_t*, hash_ptr_ops> delete_nodes;
 | 
							pool<maccnode_t*> delete_nodes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (auto &it : sig_macc)
 | 
							for (auto &it : sig_macc)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -233,10 +233,9 @@ struct ClockgatePass : public Pass {
 | 
				
			||||||
		SigBit ce_bit;
 | 
							SigBit ce_bit;
 | 
				
			||||||
		bool pol_clk;
 | 
							bool pol_clk;
 | 
				
			||||||
		bool pol_ce;
 | 
							bool pol_ce;
 | 
				
			||||||
		unsigned int hash() const {
 | 
							Hasher hash_into(Hasher h) const {
 | 
				
			||||||
			auto t = std::make_tuple(clk_bit, ce_bit, pol_clk, pol_ce);
 | 
								auto t = std::make_tuple(clk_bit, ce_bit, pol_clk, pol_ce);
 | 
				
			||||||
			unsigned int h = mkhash_init;
 | 
								h.eat(t);
 | 
				
			||||||
			h = mkhash(h, hash_ops<decltype(t)>::hash(t));
 | 
					 | 
				
			||||||
			return h;
 | 
								return h;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		bool operator==(const ClkNetInfo& other) const {
 | 
							bool operator==(const ClkNetInfo& other) const {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -250,9 +250,11 @@ struct FlowGraph
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return !(*this == other);
 | 
								return !(*this == other);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		unsigned int hash() const
 | 
							Hasher hash_into(Hasher h) const
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return hash_ops<pair<RTLIL::SigBit, int>>::hash({node, is_bottom});
 | 
								std::pair<RTLIL::SigBit, int> p = {node, is_bottom};
 | 
				
			||||||
 | 
								h.eat(p);
 | 
				
			||||||
 | 
								return h;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		static NodePrime top(RTLIL::SigBit node)
 | 
							static NodePrime top(RTLIL::SigBit node)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -53,7 +53,7 @@ struct QlDspSimdPass : public Pass {
 | 
				
			||||||
		DspConfig(const DspConfig &ref) = default;
 | 
							DspConfig(const DspConfig &ref) = default;
 | 
				
			||||||
		DspConfig(DspConfig &&ref) = default;
 | 
							DspConfig(DspConfig &&ref) = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		unsigned int hash() const { return connections.hash(); }
 | 
							Hasher hash_into(Hasher h) const { h.eat(connections); return h; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bool operator==(const DspConfig &ref) const { return connections == ref.connections; }
 | 
							bool operator==(const DspConfig &ref) const { return connections == ref.connections; }
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
set -eu
 | 
					set -eu
 | 
				
			||||||
source ../../gen-tests-makefile.sh
 | 
					source ../../gen-tests-makefile.sh
 | 
				
			||||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
					generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
set -eu
 | 
					set -eu
 | 
				
			||||||
source ../../gen-tests-makefile.sh
 | 
					source ../../gen-tests-makefile.sh
 | 
				
			||||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
					generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
set -eu
 | 
					set -eu
 | 
				
			||||||
source ../../gen-tests-makefile.sh
 | 
					source ../../gen-tests-makefile.sh
 | 
				
			||||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
					generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
set -eu
 | 
					set -eu
 | 
				
			||||||
source ../../gen-tests-makefile.sh
 | 
					source ../../gen-tests-makefile.sh
 | 
				
			||||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
					generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
set -eu
 | 
					set -eu
 | 
				
			||||||
source ../../gen-tests-makefile.sh
 | 
					source ../../gen-tests-makefile.sh
 | 
				
			||||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
					generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
set -eu
 | 
					set -eu
 | 
				
			||||||
source ../../gen-tests-makefile.sh
 | 
					source ../../gen-tests-makefile.sh
 | 
				
			||||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
					generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
set -eu
 | 
					set -eu
 | 
				
			||||||
source ../../gen-tests-makefile.sh
 | 
					source ../../gen-tests-makefile.sh
 | 
				
			||||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
					generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
set -eu
 | 
					set -eu
 | 
				
			||||||
source ../../gen-tests-makefile.sh
 | 
					source ../../gen-tests-makefile.sh
 | 
				
			||||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
					generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
set -eu
 | 
					set -eu
 | 
				
			||||||
source ../../gen-tests-makefile.sh
 | 
					source ../../gen-tests-makefile.sh
 | 
				
			||||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
					generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
set -eu
 | 
					set -eu
 | 
				
			||||||
source ../../gen-tests-makefile.sh
 | 
					source ../../gen-tests-makefile.sh
 | 
				
			||||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
					generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
set -eu
 | 
					set -eu
 | 
				
			||||||
source ../../gen-tests-makefile.sh
 | 
					source ../../gen-tests-makefile.sh
 | 
				
			||||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
					generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
set -eu
 | 
					set -eu
 | 
				
			||||||
source ../../../gen-tests-makefile.sh
 | 
					source ../../../gen-tests-makefile.sh
 | 
				
			||||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
					generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,4 +2,4 @@
 | 
				
			||||||
set -eu
 | 
					set -eu
 | 
				
			||||||
python3 mem_gen.py
 | 
					python3 mem_gen.py
 | 
				
			||||||
source ../../../gen-tests-makefile.sh
 | 
					source ../../../gen-tests-makefile.sh
 | 
				
			||||||
run_tests --yosys-scripts --bash
 | 
					generate_mk --yosys-scripts --bash
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
set -eu
 | 
					set -eu
 | 
				
			||||||
source ../../gen-tests-makefile.sh
 | 
					source ../../gen-tests-makefile.sh
 | 
				
			||||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
					generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,7 @@ YOSYS_BASEDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")"/../ >/dev/null 2>&1 && pwd)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# $ generate_target target_name test_command
 | 
					# $ generate_target target_name test_command
 | 
				
			||||||
generate_target() {
 | 
					generate_target() {
 | 
				
			||||||
	target_name=$1
 | 
						target_name=$(basename $PWD)-$1
 | 
				
			||||||
	test_command=$2
 | 
						test_command=$2
 | 
				
			||||||
	echo "all: $target_name"
 | 
						echo "all: $target_name"
 | 
				
			||||||
	echo ".PHONY: $target_name"
 | 
						echo ".PHONY: $target_name"
 | 
				
			||||||
| 
						 | 
					@ -105,7 +105,6 @@ generate_tests() {
 | 
				
			||||||
	fi
 | 
						fi
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
run_tests() {
 | 
					generate_mk() {
 | 
				
			||||||
	generate_tests "$@" > run-test.mk
 | 
						generate_tests "$@" > run-test.mk
 | 
				
			||||||
	exec ${MAKE:-make} -f run-test.mk
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
set -eu
 | 
					set -eu
 | 
				
			||||||
source ../gen-tests-makefile.sh
 | 
					source ../gen-tests-makefile.sh
 | 
				
			||||||
run_tests --yosys-scripts
 | 
					generate_mk --yosys-scripts
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
set -eu
 | 
					set -eu
 | 
				
			||||||
source ../gen-tests-makefile.sh
 | 
					source ../gen-tests-makefile.sh
 | 
				
			||||||
run_tests --yosys-scripts
 | 
					generate_mk --yosys-scripts
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,4 +9,4 @@ find tb/* -name tb*.v | while read name; do
 | 
				
			||||||
    iverilog -o tb/$test_name.out $name $verilog_name
 | 
					    iverilog -o tb/$test_name.out $name $verilog_name
 | 
				
			||||||
    ./tb/$test_name.out -fst
 | 
					    ./tb/$test_name.out -fst
 | 
				
			||||||
done
 | 
					done
 | 
				
			||||||
run_tests --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
					generate_mk --yosys-scripts --bash --yosys-args "-w 'Yosys has only limited support for tri-state logic at the moment.'"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
set -eu
 | 
					set -eu
 | 
				
			||||||
source ../gen-tests-makefile.sh
 | 
					source ../gen-tests-makefile.sh
 | 
				
			||||||
run_tests --yosys-scripts --prove-sv
 | 
					generate_mk --yosys-scripts --prove-sv
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
set -eu
 | 
					set -eu
 | 
				
			||||||
source ../gen-tests-makefile.sh
 | 
					source ../gen-tests-makefile.sh
 | 
				
			||||||
run_tests --yosys-scripts --tcl-scripts --bash --yosys-args "-e 'select out of bounds'"
 | 
					generate_mk --yosys-scripts --tcl-scripts --bash --yosys-args "-e 'select out of bounds'"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
set -eu
 | 
					set -eu
 | 
				
			||||||
source ../gen-tests-makefile.sh
 | 
					source ../gen-tests-makefile.sh
 | 
				
			||||||
run_tests --yosys-scripts --bash
 | 
					generate_mk --yosys-scripts --bash
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
set -eu
 | 
					set -eu
 | 
				
			||||||
source ../gen-tests-makefile.sh
 | 
					source ../gen-tests-makefile.sh
 | 
				
			||||||
run_tests --yosys-scripts --bash
 | 
					generate_mk --yosys-scripts --bash
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
set -eu
 | 
					set -eu
 | 
				
			||||||
source ../gen-tests-makefile.sh
 | 
					source ../gen-tests-makefile.sh
 | 
				
			||||||
run_tests --yosys-scripts --bash
 | 
					generate_mk --yosys-scripts --bash
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue