From 26a3478d8dc8401f393e6a6339b0c1a4d6ae98ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 24 Oct 2024 11:33:53 +0200 Subject: [PATCH 01/83] Drop timestamp in generate_bram_types_sim.py I'm working on build reproducibility of Fedora packages, and this patch fixes an issue observed in test rebuilds: the timestamp was set to the actual time of the build, making builds nonreproducible. Other "Generated by" strings do not include a timestamp, so drop it here too. --- techlibs/quicklogic/qlf_k6n10f/generate_bram_types_sim.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/techlibs/quicklogic/qlf_k6n10f/generate_bram_types_sim.py b/techlibs/quicklogic/qlf_k6n10f/generate_bram_types_sim.py index e57c04a08..65bb25476 100644 --- a/techlibs/quicklogic/qlf_k6n10f/generate_bram_types_sim.py +++ b/techlibs/quicklogic/qlf_k6n10f/generate_bram_types_sim.py @@ -1,10 +1,9 @@ import sys -from datetime import datetime, timezone def generate(filename): with open(filename, "w") as f: f.write("// **AUTOGENERATED FILE** **DO NOT EDIT**\n") - f.write(f"// Generated by {sys.argv[0]} at {datetime.now(timezone.utc)}\n") + f.write(f"// Generated by {sys.argv[0]}\n") f.write("`timescale 1ns /10ps\n") for a_width in [1,2,4,9,18,36]: From 6c3ae946ba5f57cf35d1decc256ee6f46302ad6a Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 11 Dec 2024 12:34:03 +0100 Subject: [PATCH 02/83] Completely remove MXE support --- Makefile | 42 ++---------------------------------------- 1 file changed, 2 insertions(+), 40 deletions(-) diff --git a/Makefile b/Makefile index 1ef5bd160..116ea4c8c 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,6 @@ CONFIG := none # CONFIG := gcc # CONFIG := afl-gcc # CONFIG := wasi -# CONFIG := mxe # CONFIG := msys2-32 # CONFIG := msys2-64 @@ -302,18 +301,6 @@ LINK_ABC := 1 DISABLE_ABC_THREADS := 1 endif -else ifeq ($(CONFIG),mxe) -PKG_CONFIG = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-pkg-config -CXX = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-g++ -CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -D_POSIX_SOURCE -Wno-attributes -CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) -LINKFLAGS := $(filter-out -rdynamic,$(LINKFLAGS)) -s -LIBS := $(filter-out -lrt,$(LIBS)) -ABCMKARGS += ARCHFLAGS="-DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w" -# TODO: Try to solve pthread linking issue in more appropriate way -ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" LINKFLAGS="-Wl,--allow-multiple-definition" ABC_USE_NO_READLINE=1 CC="/usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc" -EXE = .exe - else ifeq ($(CONFIG),msys2-32) CXX = i686-w64-mingw32-g++ CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR @@ -340,7 +327,7 @@ ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H $(ABC_ARCHFLAGS)" LTOFLAGS = else -$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, mxe, msys2-32, msys2-64, none) +$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, msys2-32, msys2-64, none) endif @@ -392,9 +379,6 @@ ifeq ($(LINK_TERMCAP),1) LIBS += -ltermcap ABCMKARGS += "ABC_READLINE_LIBRARIES=-lreadline -ltermcap" endif -ifeq ($(CONFIG),mxe) -LIBS += -ltermcap -endif else ifeq ($(ENABLE_EDITLINE),1) CXXFLAGS += -DYOSYS_ENABLE_EDITLINE @@ -443,17 +427,12 @@ TCL_INCLUDE ?= /usr/include/$(TCL_VERSION) TCL_LIBS ?= -l$(TCL_VERSION) endif -ifeq ($(CONFIG),mxe) -CXXFLAGS += -DYOSYS_ENABLE_TCL -LIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32 -lz -luserenv -else CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags tcl || echo -I$(TCL_INCLUDE)) -DYOSYS_ENABLE_TCL LIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs tcl || echo $(TCL_LIBS)) ifneq (,$(findstring TCL_WITH_EXTERNAL_TOMMATH,$(CXXFLAGS))) LIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs libtommath || echo) endif endif -endif ifeq ($(ENABLE_GCOV),1) CXXFLAGS += --coverage @@ -1101,19 +1080,6 @@ vcxsrc: $(GENFILES) $(EXTRA_TARGETS) zip -r yosys-win32-vcxsrc-$(YOSYS_VER).zip yosys-win32-vcxsrc-$(YOSYS_VER)/ rm -f srcfiles.txt kernel/version.cc -ifeq ($(CONFIG),mxe) -mxebin: $(TARGETS) $(EXTRA_TARGETS) - rm -rf yosys-win32-mxebin-$(YOSYS_VER){,.zip} - mkdir -p yosys-win32-mxebin-$(YOSYS_VER) - cp -r $(PROGRAM_PREFIX)yosys.exe share/ yosys-win32-mxebin-$(YOSYS_VER)/ -ifeq ($(ENABLE_ABC),1) - cp -r $(PROGRAM_PREFIX)yosys-abc.exe abc/lib/x86/pthreadVC2.dll yosys-win32-mxebin-$(YOSYS_VER)/ -endif - echo -en 'This is Yosys $(YOSYS_VER) for Win32.\r\n' > yosys-win32-mxebin-$(YOSYS_VER)/readme.txt - echo -en 'Documentation at https://yosyshq.net/yosys/.\r\n' >> yosys-win32-mxebin-$(YOSYS_VER)/readme.txt - zip -r yosys-win32-mxebin-$(YOSYS_VER).zip yosys-win32-mxebin-$(YOSYS_VER)/ -endif - config-clean: clean rm -f Makefile.conf @@ -1140,10 +1106,6 @@ config-wasi: clean echo 'ENABLE_READLINE := 0' >> Makefile.conf echo 'ENABLE_ZLIB := 0' >> Makefile.conf -config-mxe: clean - echo 'CONFIG := mxe' > Makefile.conf - echo 'ENABLE_PLUGINS := 0' >> Makefile.conf - config-msys2-32: clean echo 'CONFIG := msys2-32' > Makefile.conf echo "PREFIX := $(MINGW_PREFIX)" >> Makefile.conf @@ -1183,5 +1145,5 @@ echo-cxx: -include kernel/*.d -include techlibs/*/*.d -.PHONY: all top-all abc test install install-abc docs clean mrproper qtcreator coverage vcxsrc mxebin +.PHONY: all top-all abc test install install-abc docs clean mrproper qtcreator coverage vcxsrc .PHONY: config-clean config-clang config-gcc config-gcc-static config-afl-gcc config-gprof config-sudo From c99941971f4afe69a01f89fface6673ac6ac7e2f Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 11 Dec 2024 12:34:48 +0100 Subject: [PATCH 03/83] remove AFL gcc support --- Makefile | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 116ea4c8c..2fd458b69 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,6 @@ CONFIG := none # CONFIG := clang # CONFIG := gcc -# CONFIG := afl-gcc # CONFIG := wasi # CONFIG := msys2-32 # CONFIG := msys2-64 @@ -264,11 +263,6 @@ ifeq ($(DISABLE_ABC_THREADS),1) ABCMKARGS += "ABC_USE_NO_PTHREADS=1" endif -else ifeq ($(CONFIG),afl-gcc) -CXX = AFL_QUIET=1 AFL_HARDEN=1 afl-gcc -CXXFLAGS += -std=$(CXXSTD) $(OPT_LEVEL) -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H" - else ifeq ($(CONFIG),cygwin) CXX = g++ CXXFLAGS += -std=gnu++11 $(OPT_LEVEL) @@ -1095,9 +1089,6 @@ config-gcc-static: clean echo 'ENABLE_READLINE := 0' >> Makefile.conf echo 'ENABLE_TCL := 0' >> Makefile.conf -config-afl-gcc: clean - echo 'CONFIG := afl-gcc' > Makefile.conf - config-wasi: clean echo 'CONFIG := wasi' > Makefile.conf echo 'ENABLE_TCL := 0' >> Makefile.conf @@ -1146,4 +1137,4 @@ echo-cxx: -include techlibs/*/*.d .PHONY: all top-all abc test install install-abc docs clean mrproper qtcreator coverage vcxsrc -.PHONY: config-clean config-clang config-gcc config-gcc-static config-afl-gcc config-gprof config-sudo +.PHONY: config-clean config-clang config-gcc config-gcc-static config-gprof config-sudo From b9e04297f81176a82d31e7bda2eb70f9df962f31 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 11 Dec 2024 12:36:21 +0100 Subject: [PATCH 04/83] Remove cygwin support, users should use gcc target for it --- Makefile | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Makefile b/Makefile index 2fd458b69..01e709ffb 100644 --- a/Makefile +++ b/Makefile @@ -263,11 +263,6 @@ ifeq ($(DISABLE_ABC_THREADS),1) ABCMKARGS += "ABC_USE_NO_PTHREADS=1" endif -else ifeq ($(CONFIG),cygwin) -CXX = g++ -CXXFLAGS += -std=gnu++11 $(OPT_LEVEL) -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H" - else ifeq ($(CONFIG),wasi) ifeq ($(WASI_SDK),) CXX = clang++ @@ -1105,9 +1100,6 @@ config-msys2-64: clean echo 'CONFIG := msys2-64' > Makefile.conf echo "PREFIX := $(MINGW_PREFIX)" >> Makefile.conf -config-cygwin: clean - echo 'CONFIG := cygwin' > Makefile.conf - config-gcov: clean echo 'CONFIG := gcc' > Makefile.conf echo 'ENABLE_GCOV := 1' >> Makefile.conf From 03033ab6d46076ed96239e09ffe5fe38775691f0 Mon Sep 17 00:00:00 2001 From: "N. Engelhardt" Date: Wed, 11 Dec 2024 16:11:02 +0100 Subject: [PATCH 05/83] add more tests for bounds attributes, fix attributes appearing in verilog --- frontends/verific/verific.cc | 2 +- tests/verific/bounds.sv | 14 ++++ tests/verific/bounds.vhd | 108 ++++++++++++++++++++++--- tests/verific/bounds.ys | 151 +++++++++++++++++++++++++++++++++-- 4 files changed, 259 insertions(+), 16 deletions(-) create mode 100644 tests/verific/bounds.sv diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 08b8c505d..30d701aae 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -433,7 +433,7 @@ void VerificImporter::import_attributes(dict &att auto type_range = nl->GetTypeRange(obj->Name()); if (!type_range) return; - if (type_range->IsTypeScalar()) { + if (nl->IsFromVhdl() && type_range->IsTypeScalar()) { const long long bottom_bound = type_range->GetScalarRangeLeftBound(); const long long top_bound = type_range->GetScalarRangeRightBound(); const unsigned bit_width = type_range->NumElements(); diff --git a/tests/verific/bounds.sv b/tests/verific/bounds.sv new file mode 100644 index 000000000..d8081f3b7 --- /dev/null +++ b/tests/verific/bounds.sv @@ -0,0 +1,14 @@ +module test ( + input ia, + output oa, + input [0:0] ib, + output [0:0] ob, + input [3:0] ic, + output [3:0] oc + ); + +assign oa = ia; +assign ob = ib; +assign oc = ic; + +endmodule diff --git a/tests/verific/bounds.vhd b/tests/verific/bounds.vhd index 14c6c34a7..084aeb4bb 100644 --- a/tests/verific/bounds.vhd +++ b/tests/verific/bounds.vhd @@ -2,17 +2,105 @@ library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; -entity work is +entity test is Port ( - a : in INTEGER range -5 to 10; - b : out INTEGER range -6 to 11 - ); -end entity work; + -- BIT type + bit_in : in BIT; + bit_out : out BIT; -architecture Behavioral of work is + -- BIT_VECTOR type + bit_vector_in : in BIT_VECTOR(3 downto 0); + bit_vector_out : out BIT_VECTOR(3 downto 0); + + -- BIT_VECTOR type with to index + bit_vector_in_to : in BIT_VECTOR(0 to 3); + bit_vector_out_to : out BIT_VECTOR(0 to 3); + + -- STD_ULOGIC type + std_ulogic_in : in STD_ULOGIC; + std_ulogic_out : out STD_ULOGIC; + + -- STD_ULOGIC_VECTOR type + std_ulogic_vector_in : in STD_ULOGIC_VECTOR(3 downto 0); + std_ulogic_vector_out : out STD_ULOGIC_VECTOR(3 downto 0); + + -- STD_ULOGIC_VECTOR type with to index + std_ulogic_vector_in_to : in STD_ULOGIC_VECTOR(0 to 3); + std_ulogic_vector_out_to : out STD_ULOGIC_VECTOR(0 to 3); + + -- STD_LOGIC type + std_logic_in : in STD_LOGIC; + std_logic_out : out STD_LOGIC; + + -- STD_LOGIC_VECTOR type + std_logic_vector_in : in STD_LOGIC_VECTOR(3 downto 0); + std_logic_vector_out : out STD_LOGIC_VECTOR(3 downto 0); + + -- STD_LOGIC_VECTOR type with to index + std_logic_vector_in_to : in STD_LOGIC_VECTOR(0 to 3); + std_logic_vector_out_to : out STD_LOGIC_VECTOR(0 to 3); + + -- SIGNED type + signed_in : in SIGNED(3 downto 0); + signed_out : out SIGNED(3 downto 0); + + -- SIGNED type with to index + signed_in_to : in SIGNED(0 to 3); + signed_out_to : out SIGNED(0 to 3); + + -- UNSIGNED type + unsigned_in : in UNSIGNED(3 downto 0); + unsigned_out : out UNSIGNED(3 downto 0); + + -- UNSIGNED type with to index + unsigned_in_to : in UNSIGNED(0 to 3); + unsigned_out_to : out UNSIGNED(0 to 3); + + -- INTEGER type without range + integer_in : in INTEGER; + integer_out : out INTEGER; + + -- INTEGER type with range + integer_with_range_in : in INTEGER range -5 to 10; + integer_with_range_out : out INTEGER range -6 to 10; + + -- INTEGER type with single value range + integer_single_value_in : in INTEGER range 5 to 5; + integer_single_value_out : out INTEGER range 5 to 5; + + -- INTEGER type with null range + integer_null_range_in : in INTEGER range 7 to -1; + integer_null_range_out : out INTEGER range 0 to -1; + + -- NATURAL type + natural_in : in NATURAL; + natural_out : out NATURAL; + + -- POSITIVE type + positive_in : in POSITIVE; + positive_out : out POSITIVE + ); +end entity test; + +architecture Behavioral of test is begin - process(a) - begin - b <= a; - end process; + bit_out <= bit_in; + bit_vector_out <= bit_vector_in; + bit_vector_out_to <= bit_vector_in_to; + std_ulogic_out <= std_ulogic_in; + std_ulogic_vector_out <= std_ulogic_vector_in; + std_ulogic_vector_out_to <= std_ulogic_vector_in_to; + std_logic_out <= std_logic_in; + std_logic_vector_out <= std_logic_vector_in; + std_logic_vector_out_to <= std_logic_vector_in_to; + signed_out <= signed_in; + signed_out_to <= signed_in_to; + unsigned_out <= unsigned_in; + unsigned_out_to <= unsigned_in_to; + integer_with_range_out <= integer_with_range_in; + integer_out <= integer_in; + integer_single_value_out <= integer_single_value_in; + integer_null_range_out <= integer_null_range_in; + natural_out <= natural_in; + positive_out <= positive_in; end architecture Behavioral; diff --git a/tests/verific/bounds.ys b/tests/verific/bounds.ys index 425af717c..412a6218a 100644 --- a/tests/verific/bounds.ys +++ b/tests/verific/bounds.ys @@ -1,6 +1,147 @@ read -vhdl bounds.vhd -verific -import work -select -assert-count 1 a:bottom_bound=5'bs11011 -select -assert-count 1 a:top_bound=5'bs01010 -select -assert-count 1 a:bottom_bound=5'bs11010 -select -assert-count 1 a:top_bound=5'bs01011 \ No newline at end of file +hierarchy -top test + +# bit: not a scalar type +select -assert-count 0 w:bit_in a:bottom_bound %i +select -assert-count 0 w:bit_in a:top_bound %i +select -assert-count 0 w:bit_out a:bottom_bound %i +select -assert-count 0 w:bit_out a:top_bound %i + +# bit_vector: not a scalar type +select -assert-count 0 w:bit_vector_in a:bottom_bound %i +select -assert-count 0 w:bit_vector_in a:top_bound %i +select -assert-count 0 w:bit_vector_out a:bottom_bound %i +select -assert-count 0 w:bit_vector_out a:top_bound %i + +# bit_vector with to index: not a scalar type +select -assert-count 0 w:bit_vector_in_to a:bottom_bound %i +select -assert-count 0 w:bit_vector_in_to a:top_bound %i +select -assert-count 0 w:bit_vector_out_to a:bottom_bound %i +select -assert-count 0 w:bit_vector_out_to a:top_bound %i + +# std_ulogic: not a scalar type +select -assert-count 0 w:std_ulogic_in a:bottom_bound %i +select -assert-count 0 w:std_ulogic_in a:top_bound %i +select -assert-count 0 w:std_ulogic_out a:bottom_bound %i +select -assert-count 0 w:std_ulogic_out a:top_bound %i + +# std_ulogic_vector: not a scalar type +select -assert-count 0 w:std_ulogic_vector_in a:bottom_bound %i +select -assert-count 0 w:std_ulogic_vector_in a:top_bound %i +select -assert-count 0 w:std_ulogic_vector_out a:bottom_bound %i +select -assert-count 0 w:std_ulogic_vector_out a:top_bound %i + +# std_ulogic_vector with to index: not a scalar type +select -assert-count 0 w:std_ulogic_vector_in_to a:bottom_bound %i +select -assert-count 0 w:std_ulogic_vector_in_to a:top_bound %i +select -assert-count 0 w:std_ulogic_vector_out_to a:bottom_bound %i +select -assert-count 0 w:std_ulogic_vector_out_to a:top_bound %i + +# std_logic: not a scalar type +select -assert-count 0 w:std_logic_in a:bottom_bound %i +select -assert-count 0 w:std_logic_in a:top_bound %i +select -assert-count 0 w:std_logic_out a:bottom_bound %i +select -assert-count 0 w:std_logic_out a:top_bound %i + +# std_logic_vector: not a scalar type +select -assert-count 0 w:std_logic_vector_in a:bottom_bound %i +select -assert-count 0 w:std_logic_vector_in a:top_bound %i +select -assert-count 0 w:std_logic_vector_out a:bottom_bound %i +select -assert-count 0 w:std_logic_vector_out a:top_bound %i + +# std_logic_vector with to index: not a scalar type +select -assert-count 0 w:std_logic_vector_in_to a:bottom_bound %i +select -assert-count 0 w:std_logic_vector_in_to a:top_bound %i +select -assert-count 0 w:std_logic_vector_out_to a:bottom_bound %i +select -assert-count 0 w:std_logic_vector_out_to a:top_bound %i + +# signed: not a scalar type +select -assert-count 0 w:signed_in a:bottom_bound %i +select -assert-count 0 w:signed_in a:top_bound %i +select -assert-count 0 w:signed_out a:bottom_bound %i +select -assert-count 0 w:signed_out a:top_bound %i + +# signed with to index: not a scalar type +select -assert-count 0 w:signed_in_to a:bottom_bound %i +select -assert-count 0 w:signed_in_to a:top_bound %i +select -assert-count 0 w:signed_out_to a:bottom_bound %i +select -assert-count 0 w:signed_out_to a:top_bound %i + +# unsigned: not a scalar type +select -assert-count 0 w:unsigned_in a:bottom_bound %i +select -assert-count 0 w:unsigned_in a:top_bound %i +select -assert-count 0 w:unsigned_out a:bottom_bound %i +select -assert-count 0 w:unsigned_out a:top_bound %i + +# unsigned with to index: not a scalar type +select -assert-count 0 w:unsigned_in_to a:bottom_bound %i +select -assert-count 0 w:unsigned_in_to a:top_bound %i +select -assert-count 0 w:unsigned_out_to a:bottom_bound %i +select -assert-count 0 w:unsigned_out_to a:top_bound %i + +# integer: scalar type +select -assert-count 1 w:integer_in a:bottom_bound=32'b10000000000000000000000000000000 %i +select -assert-count 1 w:integer_in a:top_bound=32'b01111111111111111111111111111111 %i +select -assert-count 1 w:integer_out a:bottom_bound=32'b10000000000000000000000000000000 %i +select -assert-count 1 w:integer_out a:top_bound=32'b01111111111111111111111111111111 %i + +# integer with range: scalar type +select -assert-count 1 w:integer_with_range_in a:bottom_bound=5'bs11011 %i +select -assert-count 1 w:integer_with_range_in a:top_bound=5'bs01010 %i +select -assert-count 1 w:integer_with_range_out a:bottom_bound=5'bs11010 %i +select -assert-count 1 w:integer_with_range_out a:top_bound=5'bs01010 %i + +# integer with single value range: scalar type +select -assert-count 1 w:integer_single_value_in a:bottom_bound=3'bs101 %i +select -assert-count 1 w:integer_single_value_in a:top_bound=3'bs101 %i +select -assert-count 1 w:integer_single_value_out a:bottom_bound=3'bs101 %i +select -assert-count 1 w:integer_single_value_out a:top_bound=3'bs101 %i + +# integer with null range: scalar type +# select -assert-count 1 w:integer_null_range_in a:bottom_bound=4'bs0111 %i +# select -assert-count 1 w:integer_null_range_in a:top_bound=4'bs1111 %i +select -assert-count 1 w:integer_null_range_out a:bottom_bound=2'bs00 %i +select -assert-count 1 w:integer_null_range_out a:top_bound=2'bs11 %i + +# natural: scalar type +select -assert-count 1 w:natural_in a:bottom_bound=31'b0000000000000000000000000000000 %i +select -assert-count 1 w:natural_in a:top_bound=31'b1111111111111111111111111111111 %i +select -assert-count 1 w:natural_out a:bottom_bound=31'b0000000000000000000000000000000 %i +select -assert-count 1 w:natural_out a:top_bound=31'b1111111111111111111111111111111 %i + +# positive: scalar type +select -assert-count 1 w:positive_in a:bottom_bound=31'b0000000000000000000000000000001 %i +select -assert-count 1 w:positive_in a:top_bound=31'b1111111111111111111111111111111 %i +select -assert-count 1 w:positive_out a:bottom_bound=31'b0000000000000000000000000000001 %i +select -assert-count 1 w:positive_out a:top_bound=31'b1111111111111111111111111111111 %i + + +# integer size changed in VHDL 2019 +design -reset +read -vhdl2019 bounds.vhd +hierarchy -top test + +# integer: scalar type +select -assert-count 1 w:integer_in a:bottom_bound=64'b1000000000000000000000000000000000000000000000000000000000000000 %i +select -assert-count 1 w:integer_in a:top_bound=64'b0111111111111111111111111111111111111111111111111111111111111111 %i +select -assert-count 1 w:integer_out a:bottom_bound=64'b1000000000000000000000000000000000000000000000000000000000000000 %i +select -assert-count 1 w:integer_out a:top_bound=64'b0111111111111111111111111111111111111111111111111111111111111111 %i + +# natural: scalar type +select -assert-count 1 w:natural_in a:bottom_bound=63'b000000000000000000000000000000000000000000000000000000000000000 %i +select -assert-count 1 w:natural_in a:top_bound=63'b111111111111111111111111111111111111111111111111111111111111111 %i +select -assert-count 1 w:natural_out a:bottom_bound=63'b000000000000000000000000000000000000000000000000000000000000000 %i +select -assert-count 1 w:natural_out a:top_bound=63'b111111111111111111111111111111111111111111111111111111111111111 %i + +# positive: scalar type +select -assert-count 1 w:positive_in a:bottom_bound=63'b000000000000000000000000000000000000000000000000000000000000001 %i +select -assert-count 1 w:positive_in a:top_bound=63'b111111111111111111111111111111111111111111111111111111111111111 %i +select -assert-count 1 w:positive_out a:bottom_bound=63'b000000000000000000000000000000000000000000000000000000000000001 %i +select -assert-count 1 w:positive_out a:top_bound=63'b111111111111111111111111111111111111111111111111111111111111111 %i + +design -reset +read -sv bounds.sv +hierarchy -top test + +select -assert-count none a:bottom_bound +select -assert-count none a:top_bound From e32e199ca89dcf4def2d9196433e8ff2a09026bf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 00:22:44 +0000 Subject: [PATCH 06/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1ef5bd160..ce11b436e 100644 --- a/Makefile +++ b/Makefile @@ -155,7 +155,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.48+0 +YOSYS_VER := 0.48+1 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 603e5eb30acbf2e2aa8b5e14f593563a14fa72b1 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 12 Dec 2024 01:28:36 +0100 Subject: [PATCH 07/83] test: every test everywhere all at once --- Makefile | 157 ++++++++++++++++++++++-------------- tests/gen-tests-makefile.sh | 4 +- 2 files changed, 98 insertions(+), 63 deletions(-) diff --git a/Makefile b/Makefile index 1ef5bd160..df72a4938 100644 --- a/Makefile +++ b/Makefile @@ -842,69 +842,104 @@ else ABCOPT="" endif -# When YOSYS_NOVERIFIC is set as a make variable, also export it to the -# enviornment, so that `YOSYS_NOVERIFIC=1 make test` _and_ -# `make test YOSYS_NOVERIFIC=1` will run with verific disabled. -ifeq ($(YOSYS_NOVERIFIC),1) -export YOSYS_NOVERIFIC + +########################### +# TESTS THAT GENERATE .MK # +########################### +PARALLEL_TEST_DIRS = +PARALLEL_TEST_DIRS += tests/arch/anlogic +PARALLEL_TEST_DIRS += tests/arch/ecp5 +PARALLEL_TEST_DIRS += tests/arch/efinix +PARALLEL_TEST_DIRS += tests/arch/gatemate +PARALLEL_TEST_DIRS += tests/arch/gowin +PARALLEL_TEST_DIRS += tests/arch/ice40 +PARALLEL_TEST_DIRS += tests/arch/intel_alm +PARALLEL_TEST_DIRS += tests/arch/machxo2 +PARALLEL_TEST_DIRS += tests/arch/microchip +PARALLEL_TEST_DIRS += tests/arch/nanoxplore +PARALLEL_TEST_DIRS += tests/arch/nexus +PARALLEL_TEST_DIRS += tests/arch/quicklogic/pp3 +PARALLEL_TEST_DIRS += tests/arch/quicklogic/qlf_k6n10f +PARALLEL_TEST_DIRS += tests/arch/xilinx +PARALLEL_TEST_DIRS += tests/opt +PARALLEL_TEST_DIRS += tests/sat +PARALLEL_TEST_DIRS += tests/sim +PARALLEL_TEST_DIRS += tests/svtypes +PARALLEL_TEST_DIRS += tests/techmap +PARALLEL_TEST_DIRS += tests/various +PARALLEL_TEST_DIRS += tests/verific +PARALLEL_TEST_DIRS += tests/verilog +# FIXME: Removed YOSYS_NOVERIFIC - temporarily? +# PARALLEL_TEST_DIRS += verific/extensions/tests/passing + +################################## +# TESTS THAT DO NOT GENERATE .MK # +################################## +SEED_TEST_DIRS = +SEED_TEST_DIRS += tests/simple +SEED_TEST_DIRS += tests/simple_abc9 +SEED_TEST_DIRS += tests/hana +SEED_TEST_DIRS += tests/asicworld +# TODO dig up why is this commented out +# SEED_TEST_DIRS += tests/realmath +SEED_TEST_DIRS += tests/share +SEED_TEST_DIRS += tests/opt_share +SEED_TEST_DIRS += tests/fsm +SEED_TEST_DIRS += tests/memlib +SEED_TEST_DIRS += tests/bram +SEED_TEST_DIRS += tests/svinterfaces +SEED_TEST_DIRS += tests/xprop +SEED_TEST_DIRS += tests/select +SEED_TEST_DIRS += tests/proc +SEED_TEST_DIRS += tests/blif +SEED_TEST_DIRS += tests/arch +SEED_TEST_DIRS += tests/rpc +SEED_TEST_DIRS += tests/memfile +SEED_TEST_DIRS += tests/fmt +SEED_TEST_DIRS += tests/cxxrtl +ifeq ($(ENABLE_FUNCTIONAL_TESTS),1) +SEED_TEST_DIRS += tests/functional endif -test: $(TARGETS) $(EXTRA_TARGETS) -ifeq ($(ENABLE_VERIFIC),1) -ifeq ($(YOSYS_NOVERIFIC),1) - @echo - @echo "Running tests without verific support due to YOSYS_NOVERIFIC=1" - @echo -else - +cd tests/verific && bash run-test.sh $(SEEDOPT) -endif -endif - +cd tests/simple && bash run-test.sh $(SEEDOPT) - +cd tests/simple_abc9 && bash run-test.sh $(SEEDOPT) - +cd tests/hana && bash run-test.sh $(SEEDOPT) - +cd tests/asicworld && bash run-test.sh $(SEEDOPT) - # +cd tests/realmath && bash run-test.sh $(SEEDOPT) - +cd tests/share && bash run-test.sh $(SEEDOPT) - +cd tests/opt_share && bash run-test.sh $(SEEDOPT) - +cd tests/fsm && bash run-test.sh $(SEEDOPT) - +cd tests/techmap && bash run-test.sh - +cd tests/memories && bash run-test.sh $(ABCOPT) $(SEEDOPT) - +cd tests/memlib && bash run-test.sh $(SEEDOPT) - +cd tests/bram && bash run-test.sh $(SEEDOPT) - +cd tests/various && bash run-test.sh - +cd tests/select && bash run-test.sh - +cd tests/sat && bash run-test.sh - +cd tests/sim && bash run-test.sh - +cd tests/svinterfaces && bash run-test.sh $(SEEDOPT) - +cd tests/svtypes && bash run-test.sh $(SEEDOPT) - +cd tests/proc && bash run-test.sh - +cd tests/blif && bash run-test.sh - +cd tests/opt && bash run-test.sh - +cd tests/aiger && bash run-test.sh $(ABCOPT) - +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 -ifeq ($(ENABLE_FUNCTIONAL_TESTS),1) - +cd tests/functional && bash run-test.sh -endif +################################ +# TESTS THAT NEED SPECIAL ARGS # +################################ + +ABC_TEST_DIRS = +ABC_TEST_DIRS += tests/memories +ABC_TEST_DIRS += tests/aiger + +############ +# THE GUTS # +############ + +# seed-tests/ is a dummy string, not a directory +.PHONY: seed-tests +seed-tests: $(SEED_TEST_DIRS:%=seed-tests/%) +.PHONY: seed-tests/% +seed-tests/%: %/run-test.sh $(TARGETS) $(EXTRA_TARGETS) + +cd $* && bash run-test.sh $(SEEDOPT) + +@echo "...passed tests in $*" + +# abcopt-tests/ is a dummy string, not a directory +.PHONY: abcopt-tests +abcopt-tests: $(ABC_TEST_DIRS:%=abcopt-tests/%) +abcopt-tests/%: %/run-test.sh $(TARGETS) $(EXTRA_TARGETS) + +cd $* && bash run-test.sh $(ABCOPT) $(SEEDOPT) + +@echo "...passed tests in $*" + +# makefile-tests/ is a dummy string, not a directory +.PHONY: makefile-tests +makefile-tests: $(PARALLEL_TEST_DIRS:%=makefile-tests/%) +# this target actually emits .mk files +%.mk: + +cd $(dir $*) && bash run-test.sh +# this one spawns submake on each +makefile-tests/%: %/run-test.mk $(TARGETS) $(EXTRA_TARGETS) + $(MAKE) -C $* -f run-test.mk + +@echo "...passed tests in $*" + +test: makefile-tests abcopt-tests seed-tests @echo "" @echo " Passed \"make test\"." @echo "" diff --git a/tests/gen-tests-makefile.sh b/tests/gen-tests-makefile.sh index b997fa12d..f73a36733 100755 --- a/tests/gen-tests-makefile.sh +++ b/tests/gen-tests-makefile.sh @@ -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=$1 + target_name=$(basename $PWD)-$1 test_command=$2 echo "all: $target_name" echo ".PHONY: $target_name" @@ -107,5 +107,5 @@ generate_tests() { run_tests() { generate_tests "$@" > run-test.mk - exec ${MAKE:-make} -f run-test.mk + # exec ${MAKE:-make} -f run-test.mk } From 378864d33beb2550eb897204853d09ebed507924 Mon Sep 17 00:00:00 2001 From: "N. Engelhardt" Date: Thu, 12 Dec 2024 11:42:39 +0100 Subject: [PATCH 08/83] bound attributes: handle vhdl null ranges --- frontends/verific/verific.cc | 24 ++++++++++------ frontends/verific/verific.h | 2 +- tests/verific/bounds.sv | 53 ++++++++++++++++++++++++++++-------- tests/verific/bounds.vhd | 3 ++ tests/verific/bounds.ys | 31 +++++++++++++++++---- 5 files changed, 88 insertions(+), 25 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 30d701aae..d39030c2d 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -407,7 +407,7 @@ static const std::string verific_unescape(const char *value) } #endif -void VerificImporter::import_attributes(dict &attributes, DesignObj *obj, Netlist *nl) +void VerificImporter::import_attributes(dict &attributes, DesignObj *obj, Netlist *nl, int wire_width_hint) { if (!obj) return; @@ -436,7 +436,15 @@ void VerificImporter::import_attributes(dict &att if (nl->IsFromVhdl() && type_range->IsTypeScalar()) { const long long bottom_bound = type_range->GetScalarRangeLeftBound(); const long long top_bound = type_range->GetScalarRangeRightBound(); - const unsigned bit_width = type_range->NumElements(); + int bit_width = type_range->LeftRangeBound()+1; + if (bit_width <= 0) { // VHDL null range + if (wire_width_hint >= 0) + bit_width = wire_width_hint; + else + bit_width = 64; //fallback, currently largest integer width that verific will allow (in vhdl2019 mode) + } else { + if (wire_width_hint >= 0) log_assert(bit_width == wire_width_hint); + } RTLIL::Const bottom_const(bottom_bound, bit_width); RTLIL::Const top_const(top_bound, bit_width); if (bottom_bound < 0 || top_bound < 0) { @@ -1499,7 +1507,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma log(" importing port %s.\n", port->Name()); RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(port->Name())); - import_attributes(wire->attributes, port, nl); + import_attributes(wire->attributes, port, nl, 1); wire->port_id = nl->IndexOf(port) + 1; @@ -1527,11 +1535,11 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(portbus->Name()), portbus->Size()); wire->start_offset = min(portbus->LeftIndex(), portbus->RightIndex()); wire->upto = portbus->IsUp(); - import_attributes(wire->attributes, portbus, nl); + import_attributes(wire->attributes, portbus, nl, portbus->Size()); SetIter si ; Port *port ; FOREACH_PORT_OF_PORTBUS(portbus, si, port) { - import_attributes(wire->attributes, port->GetNet(), nl); + import_attributes(wire->attributes, port->GetNet(), nl, portbus->Size()); break; } bool portbus_input = portbus->GetDir() == DIR_INOUT || portbus->GetDir() == DIR_IN; @@ -1693,7 +1701,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma log(" importing net %s as %s.\n", net->Name(), log_id(wire_name)); RTLIL::Wire *wire = module->addWire(wire_name); - import_attributes(wire->attributes, net, nl); + import_attributes(wire->attributes, net, nl, 1); net_map[net] = wire; } @@ -1722,10 +1730,10 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma MapIter mibus; FOREACH_NET_OF_NETBUS(netbus, mibus, net) { if (net) - import_attributes(wire->attributes, net, nl); + import_attributes(wire->attributes, net, nl, netbus->Size()); break; } - import_attributes(wire->attributes, netbus, nl); + import_attributes(wire->attributes, netbus, nl, netbus->Size()); RTLIL::Const initval = Const(State::Sx, GetSize(wire)); bool initval_valid = false; diff --git a/frontends/verific/verific.h b/frontends/verific/verific.h index 0b9616e19..3c77dd7c3 100644 --- a/frontends/verific/verific.h +++ b/frontends/verific/verific.h @@ -81,7 +81,7 @@ struct VerificImporter RTLIL::SigBit net_map_at(Verific::Net *net); RTLIL::IdString new_verific_id(Verific::DesignObj *obj); - void import_attributes(dict &attributes, Verific::DesignObj *obj, Verific::Netlist *nl = nullptr); + void import_attributes(dict &attributes, Verific::DesignObj *obj, Verific::Netlist *nl = nullptr, int wire_width_hint = -1); RTLIL::SigBit netToSigBit(Verific::Net *net); RTLIL::SigSpec operatorInput(Verific::Instance *inst); diff --git a/tests/verific/bounds.sv b/tests/verific/bounds.sv index d8081f3b7..b20d02369 100644 --- a/tests/verific/bounds.sv +++ b/tests/verific/bounds.sv @@ -1,14 +1,45 @@ -module test ( - input ia, - output oa, - input [0:0] ib, - output [0:0] ob, - input [3:0] ic, - output [3:0] oc - ); +typedef enum {IDLE, RUN, STOP} state_t; -assign oa = ia; -assign ob = ib; -assign oc = ic; +typedef struct { + logic [7:0] field1; + int field2; +} my_struct_t; + +// Submodule to handle the interface ports +module submodule ( + my_ifc i_ifc, + my_ifc o_ifc +); + // Connect the interface signals + assign o_ifc.data = i_ifc.data; +endmodule + +module test ( + input i_a, + output o_a, + input [0:0] i_b, + output [0:0] o_b, + input [3:0] i_c, + output [3:0] o_c, + input logic i_d, + output logic o_d, + input bit [7:0] i_e, + output bit [7:0] o_e, + input int i_f, + output int o_f, + input state_t i_h, + output state_t o_h, + input my_struct_t i_i, + output my_struct_t o_i +); + + assign o_a = i_a; + assign o_b = i_b; + assign o_c = i_c; + assign o_d = i_d; + assign o_e = i_e; + assign o_f = i_f; + assign o_h = i_h; + assign o_i = i_i; endmodule diff --git a/tests/verific/bounds.vhd b/tests/verific/bounds.vhd index 084aeb4bb..782f3b5ad 100644 --- a/tests/verific/bounds.vhd +++ b/tests/verific/bounds.vhd @@ -83,6 +83,7 @@ entity test is end entity test; architecture Behavioral of test is + signal integer_with_range : INTEGER range -1 to 100; begin bit_out <= bit_in; bit_vector_out <= bit_vector_in; @@ -103,4 +104,6 @@ begin integer_null_range_out <= integer_null_range_in; natural_out <= natural_in; positive_out <= positive_in; + + integer_with_range <= 42; end architecture Behavioral; diff --git a/tests/verific/bounds.ys b/tests/verific/bounds.ys index 412a6218a..317086264 100644 --- a/tests/verific/bounds.ys +++ b/tests/verific/bounds.ys @@ -98,10 +98,10 @@ select -assert-count 1 w:integer_single_value_out a:bottom_bound=3'bs101 %i select -assert-count 1 w:integer_single_value_out a:top_bound=3'bs101 %i # integer with null range: scalar type -# select -assert-count 1 w:integer_null_range_in a:bottom_bound=4'bs0111 %i -# select -assert-count 1 w:integer_null_range_in a:top_bound=4'bs1111 %i -select -assert-count 1 w:integer_null_range_out a:bottom_bound=2'bs00 %i -select -assert-count 1 w:integer_null_range_out a:top_bound=2'bs11 %i +select -assert-count 1 w:integer_null_range_in a:bottom_bound=4'bs0111 %i +select -assert-count 1 w:integer_null_range_in a:top_bound=4'bs1111 %i +select -assert-count 1 w:integer_null_range_out a:bottom_bound=1'bs0 %i +select -assert-count 1 w:integer_null_range_out a:top_bound=1'bs1 %i # natural: scalar type select -assert-count 1 w:natural_in a:bottom_bound=31'b0000000000000000000000000000000 %i @@ -116,11 +116,11 @@ select -assert-count 1 w:positive_out a:bottom_bound=31'b00000000000000000000000 select -assert-count 1 w:positive_out a:top_bound=31'b1111111111111111111111111111111 %i -# integer size changed in VHDL 2019 design -reset read -vhdl2019 bounds.vhd hierarchy -top test +## integer size changed in VHDL 2019 # integer: scalar type select -assert-count 1 w:integer_in a:bottom_bound=64'b1000000000000000000000000000000000000000000000000000000000000000 %i select -assert-count 1 w:integer_in a:top_bound=64'b0111111111111111111111111111111111111111111111111111111111111111 %i @@ -139,9 +139,30 @@ select -assert-count 1 w:positive_in a:top_bound=63'b111111111111111111111111111 select -assert-count 1 w:positive_out a:bottom_bound=63'b000000000000000000000000000000000000000000000000000000000000001 %i select -assert-count 1 w:positive_out a:top_bound=63'b111111111111111111111111111111111111111111111111111111111111111 %i +## ranged integer sizes should be unaffected +# integer with range: scalar type +select -assert-count 1 w:integer_with_range_in a:bottom_bound=5'bs11011 %i +select -assert-count 1 w:integer_with_range_in a:top_bound=5'bs01010 %i +select -assert-count 1 w:integer_with_range_out a:bottom_bound=5'bs11010 %i +select -assert-count 1 w:integer_with_range_out a:top_bound=5'bs01010 %i + +# integer with single value range: scalar type +select -assert-count 1 w:integer_single_value_in a:bottom_bound=3'bs101 %i +select -assert-count 1 w:integer_single_value_in a:top_bound=3'bs101 %i +select -assert-count 1 w:integer_single_value_out a:bottom_bound=3'bs101 %i +select -assert-count 1 w:integer_single_value_out a:top_bound=3'bs101 %i + +# integer with null range: scalar type +select -assert-count 1 w:integer_null_range_in a:bottom_bound=4'bs0111 %i +select -assert-count 1 w:integer_null_range_in a:top_bound=4'bs1111 %i +select -assert-count 1 w:integer_null_range_out a:bottom_bound=1'bs0 %i +select -assert-count 1 w:integer_null_range_out a:top_bound=1'bs1 %i + + design -reset read -sv bounds.sv hierarchy -top test +## bounds should not be generated for SV select -assert-count none a:bottom_bound select -assert-count none a:top_bound From 4581f75b03a25b615a9715516854c424b580f7ab Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2024 00:23:01 +0000 Subject: [PATCH 09/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ce11b436e..c1dfc2ad2 100644 --- a/Makefile +++ b/Makefile @@ -155,7 +155,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.48+1 +YOSYS_VER := 0.48+5 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 6240aec4333078094ebe0c0f8c81a2d3b2905096 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Fri, 13 Dec 2024 10:24:47 +0100 Subject: [PATCH 10/83] test: restore verific handling, nicer naming --- Makefile | 132 +++++++++---------- tests/arch/anlogic/run-test.sh | 2 +- tests/arch/ecp5/run-test.sh | 2 +- tests/arch/efinix/run-test.sh | 2 +- tests/arch/gatemate/run-test.sh | 2 +- tests/arch/gowin/run-test.sh | 2 +- tests/arch/ice40/run-test.sh | 2 +- tests/arch/intel_alm/run-test.sh | 2 +- tests/arch/machxo2/run-test.sh | 2 +- tests/arch/microchip/run-test.sh | 2 +- tests/arch/nanoxplore/run-test.sh | 2 +- tests/arch/nexus/run-test.sh | 2 +- tests/arch/quicklogic/pp3/run-test.sh | 2 +- tests/arch/quicklogic/qlf_k6n10f/run-test.sh | 2 +- tests/arch/xilinx/run-test.sh | 2 +- tests/gen-tests-makefile.sh | 3 +- tests/opt/run-test.sh | 2 +- tests/sat/run-test.sh | 2 +- tests/sim/run-test.sh | 2 +- tests/svtypes/run-test.sh | 2 +- tests/techmap/run-test.sh | 2 +- tests/various/run-test.sh | 2 +- tests/verific/run-test.sh | 2 +- tests/verilog/run-test.sh | 2 +- 24 files changed, 86 insertions(+), 93 deletions(-) diff --git a/Makefile b/Makefile index df72a4938..10c8aa9b0 100644 --- a/Makefile +++ b/Makefile @@ -842,80 +842,69 @@ else ABCOPT="" endif +# Tests that generate .mk with tests/gen-tests-makefile.sh +MK_TEST_DIRS = +MK_TEST_DIRS += tests/arch/anlogic +MK_TEST_DIRS += tests/arch/ecp5 +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 GENERATE .MK # -########################### -PARALLEL_TEST_DIRS = -PARALLEL_TEST_DIRS += tests/arch/anlogic -PARALLEL_TEST_DIRS += tests/arch/ecp5 -PARALLEL_TEST_DIRS += tests/arch/efinix -PARALLEL_TEST_DIRS += tests/arch/gatemate -PARALLEL_TEST_DIRS += tests/arch/gowin -PARALLEL_TEST_DIRS += tests/arch/ice40 -PARALLEL_TEST_DIRS += tests/arch/intel_alm -PARALLEL_TEST_DIRS += tests/arch/machxo2 -PARALLEL_TEST_DIRS += tests/arch/microchip -PARALLEL_TEST_DIRS += tests/arch/nanoxplore -PARALLEL_TEST_DIRS += tests/arch/nexus -PARALLEL_TEST_DIRS += tests/arch/quicklogic/pp3 -PARALLEL_TEST_DIRS += tests/arch/quicklogic/qlf_k6n10f -PARALLEL_TEST_DIRS += tests/arch/xilinx -PARALLEL_TEST_DIRS += tests/opt -PARALLEL_TEST_DIRS += tests/sat -PARALLEL_TEST_DIRS += tests/sim -PARALLEL_TEST_DIRS += tests/svtypes -PARALLEL_TEST_DIRS += tests/techmap -PARALLEL_TEST_DIRS += tests/various -PARALLEL_TEST_DIRS += tests/verific -PARALLEL_TEST_DIRS += tests/verilog -# FIXME: Removed YOSYS_NOVERIFIC - temporarily? -# PARALLEL_TEST_DIRS += verific/extensions/tests/passing - -################################## -# TESTS THAT DO NOT GENERATE .MK # -################################## -SEED_TEST_DIRS = -SEED_TEST_DIRS += tests/simple -SEED_TEST_DIRS += tests/simple_abc9 -SEED_TEST_DIRS += tests/hana -SEED_TEST_DIRS += tests/asicworld -# TODO dig up why is this commented out -# SEED_TEST_DIRS += tests/realmath -SEED_TEST_DIRS += tests/share -SEED_TEST_DIRS += tests/opt_share -SEED_TEST_DIRS += tests/fsm -SEED_TEST_DIRS += tests/memlib -SEED_TEST_DIRS += tests/bram -SEED_TEST_DIRS += tests/svinterfaces -SEED_TEST_DIRS += tests/xprop -SEED_TEST_DIRS += tests/select -SEED_TEST_DIRS += tests/proc -SEED_TEST_DIRS += tests/blif -SEED_TEST_DIRS += tests/arch -SEED_TEST_DIRS += tests/rpc -SEED_TEST_DIRS += tests/memfile -SEED_TEST_DIRS += tests/fmt -SEED_TEST_DIRS += tests/cxxrtl +# 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) -SEED_TEST_DIRS += tests/functional +SH_TEST_DIRS += tests/functional endif -################################ -# TESTS THAT NEED SPECIAL ARGS # -################################ - -ABC_TEST_DIRS = -ABC_TEST_DIRS += tests/memories -ABC_TEST_DIRS += tests/aiger - -############ -# THE GUTS # -############ +# Tests that don't generate .mk and need special args +SH_ABC_TEST_DIRS = +SH_ABC_TEST_DIRS += tests/memories +SH_ABC_TEST_DIRS += tests/aiger # seed-tests/ is a dummy string, not a directory .PHONY: seed-tests -seed-tests: $(SEED_TEST_DIRS:%=seed-tests/%) +seed-tests: $(SH_TEST_DIRS:%=seed-tests/%) .PHONY: seed-tests/% seed-tests/%: %/run-test.sh $(TARGETS) $(EXTRA_TARGETS) +cd $* && bash run-test.sh $(SEEDOPT) @@ -923,14 +912,14 @@ seed-tests/%: %/run-test.sh $(TARGETS) $(EXTRA_TARGETS) # abcopt-tests/ is a dummy string, not a directory .PHONY: abcopt-tests -abcopt-tests: $(ABC_TEST_DIRS:%=abcopt-tests/%) +abcopt-tests: $(SH_ABC_TEST_DIRS:%=abcopt-tests/%) abcopt-tests/%: %/run-test.sh $(TARGETS) $(EXTRA_TARGETS) +cd $* && bash run-test.sh $(ABCOPT) $(SEEDOPT) +@echo "...passed tests in $*" # makefile-tests/ is a dummy string, not a directory .PHONY: makefile-tests -makefile-tests: $(PARALLEL_TEST_DIRS:%=makefile-tests/%) +makefile-tests: $(MK_TEST_DIRS:%=makefile-tests/%) # this target actually emits .mk files %.mk: +cd $(dir $*) && bash run-test.sh @@ -942,6 +931,11 @@ makefile-tests/%: %/run-test.mk $(TARGETS) $(EXTRA_TARGETS) test: makefile-tests abcopt-tests seed-tests @echo "" @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 "" VALGRIND ?= valgrind --error-exitcode=1 --leak-check=full --show-reachable=yes --errors-for-leak-kinds=all diff --git a/tests/arch/anlogic/run-test.sh b/tests/arch/anlogic/run-test.sh index 4be4b70ae..691b70966 100755 --- a/tests/arch/anlogic/run-test.sh +++ b/tests/arch/anlogic/run-test.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash set -eu 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.'" diff --git a/tests/arch/ecp5/run-test.sh b/tests/arch/ecp5/run-test.sh index 4be4b70ae..691b70966 100755 --- a/tests/arch/ecp5/run-test.sh +++ b/tests/arch/ecp5/run-test.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash set -eu 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.'" diff --git a/tests/arch/efinix/run-test.sh b/tests/arch/efinix/run-test.sh index 4be4b70ae..691b70966 100755 --- a/tests/arch/efinix/run-test.sh +++ b/tests/arch/efinix/run-test.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash set -eu 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.'" diff --git a/tests/arch/gatemate/run-test.sh b/tests/arch/gatemate/run-test.sh index 4be4b70ae..691b70966 100755 --- a/tests/arch/gatemate/run-test.sh +++ b/tests/arch/gatemate/run-test.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash set -eu 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.'" diff --git a/tests/arch/gowin/run-test.sh b/tests/arch/gowin/run-test.sh index 4be4b70ae..691b70966 100755 --- a/tests/arch/gowin/run-test.sh +++ b/tests/arch/gowin/run-test.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash set -eu 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.'" diff --git a/tests/arch/ice40/run-test.sh b/tests/arch/ice40/run-test.sh index 4be4b70ae..691b70966 100755 --- a/tests/arch/ice40/run-test.sh +++ b/tests/arch/ice40/run-test.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash set -eu 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.'" diff --git a/tests/arch/intel_alm/run-test.sh b/tests/arch/intel_alm/run-test.sh index 4be4b70ae..691b70966 100755 --- a/tests/arch/intel_alm/run-test.sh +++ b/tests/arch/intel_alm/run-test.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash set -eu 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.'" diff --git a/tests/arch/machxo2/run-test.sh b/tests/arch/machxo2/run-test.sh index 4be4b70ae..691b70966 100644 --- a/tests/arch/machxo2/run-test.sh +++ b/tests/arch/machxo2/run-test.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash set -eu 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.'" diff --git a/tests/arch/microchip/run-test.sh b/tests/arch/microchip/run-test.sh index 4be4b70ae..691b70966 100755 --- a/tests/arch/microchip/run-test.sh +++ b/tests/arch/microchip/run-test.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash set -eu 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.'" diff --git a/tests/arch/nanoxplore/run-test.sh b/tests/arch/nanoxplore/run-test.sh index 4be4b70ae..691b70966 100755 --- a/tests/arch/nanoxplore/run-test.sh +++ b/tests/arch/nanoxplore/run-test.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash set -eu 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.'" diff --git a/tests/arch/nexus/run-test.sh b/tests/arch/nexus/run-test.sh index 4be4b70ae..691b70966 100644 --- a/tests/arch/nexus/run-test.sh +++ b/tests/arch/nexus/run-test.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash set -eu 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.'" diff --git a/tests/arch/quicklogic/pp3/run-test.sh b/tests/arch/quicklogic/pp3/run-test.sh index 3f8515f9a..43a7874b2 100755 --- a/tests/arch/quicklogic/pp3/run-test.sh +++ b/tests/arch/quicklogic/pp3/run-test.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash set -eu 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.'" diff --git a/tests/arch/quicklogic/qlf_k6n10f/run-test.sh b/tests/arch/quicklogic/qlf_k6n10f/run-test.sh index 2fe336194..c7daba12d 100755 --- a/tests/arch/quicklogic/qlf_k6n10f/run-test.sh +++ b/tests/arch/quicklogic/qlf_k6n10f/run-test.sh @@ -2,4 +2,4 @@ set -eu python3 mem_gen.py source ../../../gen-tests-makefile.sh -run_tests --yosys-scripts --bash +generate_mk --yosys-scripts --bash diff --git a/tests/arch/xilinx/run-test.sh b/tests/arch/xilinx/run-test.sh index 4be4b70ae..691b70966 100755 --- a/tests/arch/xilinx/run-test.sh +++ b/tests/arch/xilinx/run-test.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash set -eu 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.'" diff --git a/tests/gen-tests-makefile.sh b/tests/gen-tests-makefile.sh index f73a36733..146bb5e81 100755 --- a/tests/gen-tests-makefile.sh +++ b/tests/gen-tests-makefile.sh @@ -105,7 +105,6 @@ generate_tests() { fi } -run_tests() { +generate_mk() { generate_tests "$@" > run-test.mk - # exec ${MAKE:-make} -f run-test.mk } diff --git a/tests/opt/run-test.sh b/tests/opt/run-test.sh index 74589dfeb..006c731e3 100755 --- a/tests/opt/run-test.sh +++ b/tests/opt/run-test.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash set -eu source ../gen-tests-makefile.sh -run_tests --yosys-scripts +generate_mk --yosys-scripts diff --git a/tests/sat/run-test.sh b/tests/sat/run-test.sh index 74589dfeb..006c731e3 100755 --- a/tests/sat/run-test.sh +++ b/tests/sat/run-test.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash set -eu source ../gen-tests-makefile.sh -run_tests --yosys-scripts +generate_mk --yosys-scripts diff --git a/tests/sim/run-test.sh b/tests/sim/run-test.sh index a5120e77e..43571e057 100755 --- a/tests/sim/run-test.sh +++ b/tests/sim/run-test.sh @@ -9,4 +9,4 @@ find tb/* -name tb*.v | while read name; do iverilog -o tb/$test_name.out $name $verilog_name ./tb/$test_name.out -fst 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.'" diff --git a/tests/svtypes/run-test.sh b/tests/svtypes/run-test.sh index 91ceae227..8b0333f27 100755 --- a/tests/svtypes/run-test.sh +++ b/tests/svtypes/run-test.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash set -eu source ../gen-tests-makefile.sh -run_tests --yosys-scripts --prove-sv +generate_mk --yosys-scripts --prove-sv diff --git a/tests/techmap/run-test.sh b/tests/techmap/run-test.sh index 16741cace..0766db999 100755 --- a/tests/techmap/run-test.sh +++ b/tests/techmap/run-test.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash set -eu 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'" diff --git a/tests/various/run-test.sh b/tests/various/run-test.sh index 2f91cf0fd..dee032827 100755 --- a/tests/various/run-test.sh +++ b/tests/various/run-test.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash set -eu source ../gen-tests-makefile.sh -run_tests --yosys-scripts --bash +generate_mk --yosys-scripts --bash diff --git a/tests/verific/run-test.sh b/tests/verific/run-test.sh index 2f91cf0fd..dee032827 100755 --- a/tests/verific/run-test.sh +++ b/tests/verific/run-test.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash set -eu source ../gen-tests-makefile.sh -run_tests --yosys-scripts --bash +generate_mk --yosys-scripts --bash diff --git a/tests/verilog/run-test.sh b/tests/verilog/run-test.sh index 2f91cf0fd..dee032827 100755 --- a/tests/verilog/run-test.sh +++ b/tests/verilog/run-test.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash set -eu source ../gen-tests-makefile.sh -run_tests --yosys-scripts --bash +generate_mk --yosys-scripts --bash From 08778917dbd8ba026382694c57c1e8a02a473455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 16 Dec 2024 12:56:44 +0100 Subject: [PATCH 11/83] wreduce: Optimize signedness when possible --- passes/opt/wreduce.cc | 51 +++++++++++++++++++++++++++++++++++++++ tests/various/wreduce2.ys | 22 +++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 tests/various/wreduce2.ys diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 02678d676..9c0fcc7e1 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -263,6 +263,19 @@ struct WreduceWorker } } + int reduced_opsize(const SigSpec &inp, bool signed_) + { + int size = GetSize(inp); + if (signed_) { + while (size >= 2 && inp[size - 1] == inp[size - 2]) + size--; + } else { + while (size >= 1 && inp[size - 1] == State::S0) + size--; + } + return size; + } + void run_cell(Cell *cell) { bool did_something = false; @@ -295,6 +308,44 @@ struct WreduceWorker bool port_a_signed = false; bool port_b_signed = false; + // Under certain conditions we are free to choose the signedness of the operands + if (cell->type.in(ID($mul), ID($add), ID($sub)) && + max_port_a_size == GetSize(sig) && + max_port_b_size == GetSize(sig)) { + SigSpec sig_a = mi.sigmap(cell->getPort(ID::A)), sig_b = mi.sigmap(cell->getPort(ID::B)); + + // Remove top bits from sig_a and sig_b which are not visible on the output + sig_a.extend_u0(max_port_a_size); + sig_b.extend_u0(max_port_b_size); + + int signed_size, unsigned_size; + if (cell->type == ID($mul)) { + signed_size = reduced_opsize(sig_a, true) * reduced_opsize(sig_b, true); + unsigned_size = reduced_opsize(sig_a, false) * reduced_opsize(sig_b, false); + } else { + signed_size = max(reduced_opsize(sig_a, true), reduced_opsize(sig_b, true)); + unsigned_size = max(reduced_opsize(sig_a, false), reduced_opsize(sig_b, false)); + } + + if (!port_a_signed && !port_b_signed && signed_size < unsigned_size) { + log("Converting cell %s.%s (%s) from unsigned to signed.\n", + log_id(module), log_id(cell), log_id(cell->type)); + cell->setParam(ID::A_SIGNED, 1); + cell->setParam(ID::B_SIGNED, 1); + port_a_signed = true; + port_b_signed = true; + did_something = true; + } else if (port_a_signed && port_b_signed && unsigned_size < signed_size) { + log("Converting cell %s.%s (%s) from signed to unsigned.\n", + log_id(module), log_id(cell), log_id(cell->type)); + cell->setParam(ID::A_SIGNED, 0); + cell->setParam(ID::B_SIGNED, 0); + port_a_signed = false; + port_b_signed = false; + did_something = true; + } + } + if (max_port_a_size >= 0 && cell->type != ID($shiftx)) run_reduce_inport(cell, 'A', max_port_a_size, port_a_signed, did_something); diff --git a/tests/various/wreduce2.ys b/tests/various/wreduce2.ys new file mode 100644 index 000000000..496aa97e9 --- /dev/null +++ b/tests/various/wreduce2.ys @@ -0,0 +1,22 @@ +read_verilog < Date: Tue, 1 Oct 2024 15:12:03 +0200 Subject: [PATCH 12/83] hashlib: redo interface for flexibility --- backends/cxxrtl/cxxrtl_backend.cc | 26 +-- examples/cxx-api/scopeinfo_example.cc | 2 +- frontends/ast/ast.h | 2 +- frontends/verific/verific.cc | 16 +- frontends/verific/verific.h | 4 +- frontends/verific/verificsva.cc | 2 +- kernel/bitpattern.h | 11 +- kernel/cellaigs.cc | 17 +- kernel/cellaigs.h | 4 +- kernel/drivertools.h | 222 +++++++++++++------ kernel/functional.h | 8 +- kernel/hashlib.h | 303 +++++++++++++++----------- kernel/log.h | 12 +- kernel/modtools.h | 20 +- kernel/rtlil.cc | 14 +- kernel/rtlil.h | 66 +++--- kernel/scopeinfo.h | 2 +- kernel/sigtools.h | 12 +- kernel/timinginfo.h | 12 +- kernel/utils.h | 12 +- kernel/yosys_common.h | 51 ++--- kernel/yw.h | 2 +- passes/cmds/dft_tag.cc | 2 +- passes/cmds/example_dt.cc | 6 +- passes/cmds/viz.cc | 38 ++-- passes/equiv/equiv_struct.cc | 10 +- passes/proc/proc_dlatch.cc | 9 +- passes/proc/proc_mux.cc | 8 +- passes/sat/mutate.cc | 2 +- passes/sat/recover_names.cc | 12 +- passes/sat/sim.cc | 2 +- passes/techmap/alumacc.cc | 6 +- passes/techmap/clockgate.cc | 5 +- passes/techmap/flowmap.cc | 6 +- techlibs/quicklogic/ql_dsp_simd.cc | 2 +- 35 files changed, 542 insertions(+), 386 deletions(-) diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index b72caf119..931454ada 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -47,7 +47,7 @@ struct Scheduler { struct Vertex { T *data; Vertex *prev, *next; - pool preds, succs; + pool preds, succs; Vertex() : data(NULL), prev(this), next(this) {} Vertex(T *data) : data(data), prev(NULL), next(NULL) {} @@ -300,10 +300,10 @@ struct FlowGraph { }; std::vector nodes; - dict> wire_comb_defs, wire_sync_defs, wire_uses; - dict, hash_ptr_ops> node_comb_defs, node_sync_defs, node_uses; + dict> wire_comb_defs, wire_sync_defs, wire_uses; + dict> node_comb_defs, node_sync_defs, node_uses; dict wire_def_inlinable; - dict> wire_use_inlinable; + dict> wire_use_inlinable; dict bit_has_state; ~FlowGraph() @@ -365,7 +365,7 @@ struct FlowGraph { return false; } - bool is_inlinable(const RTLIL::Wire *wire, const pool &nodes) const + bool is_inlinable(const RTLIL::Wire *wire, const pool &nodes) const { // Can the wire be inlined, knowing that the given nodes are reachable? if (nodes.size() != 1) @@ -3080,7 +3080,7 @@ struct CxxrtlWorker { // without feedback arcs can generally be evaluated in a single pass, i.e. it always requires only // a single delta cycle. Scheduler scheduler; - dict::Vertex*, hash_ptr_ops> node_vertex_map; + dict::Vertex*> node_vertex_map; for (auto node : flow.nodes) node_vertex_map[node] = scheduler.add(node); for (auto node_comb_def : flow.node_comb_defs) { @@ -3095,7 +3095,7 @@ struct CxxrtlWorker { // Find out whether the order includes any feedback arcs. std::vector node_order; - pool evaluated_nodes; + pool evaluated_nodes; pool feedback_wires; for (auto vertex : scheduler.schedule()) { auto node = vertex->data; @@ -3139,7 +3139,7 @@ struct CxxrtlWorker { } // Discover nodes reachable from primary outputs (i.e. members) and collect reachable wire users. - pool worklist; + pool worklist; for (auto node : flow.nodes) { if (node->type == FlowGraph::Node::Type::CELL_EVAL && !is_internal_cell(node->cell->type)) worklist.insert(node); // node evaluates a submodule @@ -3159,8 +3159,8 @@ struct CxxrtlWorker { worklist.insert(node); // node drives public wires } } - dict> live_wires; - pool live_nodes; + dict> live_wires; + pool live_nodes; while (!worklist.empty()) { auto node = worklist.pop(); live_nodes.insert(node); @@ -3290,15 +3290,15 @@ struct CxxrtlWorker { // Discover nodes reachable from primary outputs (i.e. outlines) up until primary inputs (i.e. members) // and collect reachable wire users. - pool worklist; + pool worklist; for (auto node : flow.nodes) { if (flow.node_comb_defs.count(node)) for (auto wire : flow.node_comb_defs[node]) if (debug_wire_types[wire].is_outline()) worklist.insert(node); // node drives outline } - dict> debug_live_wires; - pool debug_live_nodes; + dict> debug_live_wires; + pool debug_live_nodes; while (!worklist.empty()) { auto node = worklist.pop(); debug_live_nodes.insert(node); diff --git a/examples/cxx-api/scopeinfo_example.cc b/examples/cxx-api/scopeinfo_example.cc index f163dff9e..0882ba804 100644 --- a/examples/cxx-api/scopeinfo_example.cc +++ b/examples/cxx-api/scopeinfo_example.cc @@ -90,7 +90,7 @@ struct ScopeinfoExamplePass : public Pass { // Shuffle wires so this example produces more interesting outputs std::sort(wires.begin(), wires.end(), [](Wire *a, Wire *b) { - return mkhash_xorshift(a->name.hash() * 0x2c9277b5) < mkhash_xorshift(b->name.hash() * 0x2c9277b5); + return mkhash_xorshift(run_hash(a->name) * 0x2c9277b5) < mkhash_xorshift(run_hash(b->name) * 0x2c9277b5); }); ModuleHdlnameIndex index(module); diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index bdff015e3..1a72e6285 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -177,7 +177,7 @@ namespace AST { // for dict<> and pool<> unsigned int hashidx_; - unsigned int hash() const { return hashidx_; } + Hasher hash_acc(Hasher h) const { h.acc(hashidx_); return h; } // this nodes type AstNodeType type; diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index d39030c2d..8f1b07b10 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -619,7 +619,7 @@ RTLIL::SigSpec VerificImporter::operatorInportCase(Instance *inst, const char *p } } -RTLIL::SigSpec VerificImporter::operatorOutput(Instance *inst, const pool *any_all_nets) +RTLIL::SigSpec VerificImporter::operatorOutput(Instance *inst, const pool *any_all_nets) { RTLIL::SigSpec sig; RTLIL::Wire *dummy_wire = NULL; @@ -1576,9 +1576,9 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma module->fixup_ports(); - dict init_nets; - pool anyconst_nets, anyseq_nets; - pool allconst_nets, allseq_nets; + dict init_nets; + pool anyconst_nets, anyseq_nets; + pool allconst_nets, allseq_nets; any_all_nets.clear(); FOREACH_NET_OF_NETLIST(nl, mi, net) @@ -1841,10 +1841,10 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma module->connect(net_map_at(net), module->Anyseq(new_verific_id(net))); #ifdef VERIFIC_SYSTEMVERILOG_SUPPORT - pool sva_asserts; - pool sva_assumes; - pool sva_covers; - pool sva_triggers; + pool sva_asserts; + pool sva_assumes; + pool sva_covers; + pool sva_triggers; #endif pool past_ffs; diff --git a/frontends/verific/verific.h b/frontends/verific/verific.h index 3c77dd7c3..4e9c7a305 100644 --- a/frontends/verific/verific.h +++ b/frontends/verific/verific.h @@ -71,7 +71,7 @@ struct VerificImporter std::map net_map; std::map sva_posedge_map; - pool any_all_nets; + pool any_all_nets; bool mode_gates, mode_keep, mode_nosva, mode_names, mode_verific; bool mode_autocover, mode_fullinit; @@ -89,7 +89,7 @@ struct VerificImporter RTLIL::SigSpec operatorInput2(Verific::Instance *inst); RTLIL::SigSpec operatorInport(Verific::Instance *inst, const char *portname); RTLIL::SigSpec operatorInportCase(Verific::Instance *inst, const char *portname); - RTLIL::SigSpec operatorOutput(Verific::Instance *inst, const pool *any_all_nets = nullptr); + RTLIL::SigSpec operatorOutput(Verific::Instance *inst, const pool *any_all_nets = nullptr); bool import_netlist_instance_gates(Verific::Instance *inst, RTLIL::IdString inst_name); bool import_netlist_instance_cells(Verific::Instance *inst, RTLIL::IdString inst_name); diff --git a/frontends/verific/verificsva.cc b/frontends/verific/verificsva.cc index ef8247e83..860d3c166 100644 --- a/frontends/verific/verificsva.cc +++ b/frontends/verific/verificsva.cc @@ -1051,7 +1051,7 @@ struct VerificSvaImporter msg.c_str(), inst->View()->Owner()->Name(), inst->Name()), inst->Linefile()); } - dict check_expression_cache; + dict check_expression_cache; bool check_expression(Net *net, bool raise_error = false) { diff --git a/kernel/bitpattern.h b/kernel/bitpattern.h index c1ceac14c..3814f4672 100644 --- a/kernel/bitpattern.h +++ b/kernel/bitpattern.h @@ -30,7 +30,7 @@ struct BitPatternPool int width; struct bits_t { std::vector bitdata; - mutable unsigned int cached_hash; + mutable Hasher::hash_t cached_hash; bits_t(int width = 0) : bitdata(width), cached_hash(0) { } RTLIL::State &operator[](int index) { return bitdata[index]; @@ -39,14 +39,15 @@ struct BitPatternPool return bitdata[index]; } bool operator==(const bits_t &other) const { - if (hash() != other.hash()) + if (run_hash(*this) != run_hash(other)) return false; return bitdata == other.bitdata; } - unsigned int hash() const { + Hasher hash_acc(Hasher h) const { if (!cached_hash) - cached_hash = hash_ops>::hash(bitdata); - return cached_hash; + cached_hash = run_hash(bitdata); + h.acc(cached_hash); + return h; } }; pool database; diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc index de0a49394..81b486c79 100644 --- a/kernel/cellaigs.cc +++ b/kernel/cellaigs.cc @@ -39,13 +39,13 @@ bool AigNode::operator==(const AigNode &other) const return true; } -unsigned int AigNode::hash() const +Hasher AigNode::hash_acc(Hasher h) const { - unsigned int h = mkhash_init; - h = mkhash(portname.hash(), portbit); - h = mkhash(h, inverter); - h = mkhash(h, left_parent); - h = mkhash(h, right_parent); + h.acc(portname); + h.acc(portbit); + h.acc(inverter); + h.acc(left_parent); + h.acc(right_parent); return h; } @@ -54,9 +54,10 @@ bool Aig::operator==(const Aig &other) const return name == other.name; } -unsigned int Aig::hash() const +Hasher Aig::hash_acc(Hasher h) const { - return hash_ops::hash(name); + h.acc(name); + return h; } struct AigMaker diff --git a/kernel/cellaigs.h b/kernel/cellaigs.h index 8f6d69ba6..bdb8b3c07 100644 --- a/kernel/cellaigs.h +++ b/kernel/cellaigs.h @@ -34,7 +34,7 @@ struct AigNode AigNode(); bool operator==(const AigNode &other) const; - unsigned int hash() const; + Hasher hash_acc(Hasher h) const; }; struct Aig @@ -44,7 +44,7 @@ struct Aig Aig(Cell *cell); bool operator==(const Aig &other) const; - unsigned int hash() const; + Hasher hash_acc(Hasher h) const; }; YOSYS_NAMESPACE_END diff --git a/kernel/drivertools.h b/kernel/drivertools.h index 8929c3426..fdead5c36 100644 --- a/kernel/drivertools.h +++ b/kernel/drivertools.h @@ -74,10 +74,8 @@ struct DriveBitWire return offset < other.offset; } - unsigned int hash() const - { - return mkhash_add(wire->name.hash(), offset); - } + Hasher hash_acc(Hasher h) const; + operator SigBit() const { @@ -107,10 +105,8 @@ struct DriveBitPort return offset < other.offset; } - unsigned int hash() const - { - return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset); - } + Hasher hash_acc(Hasher h) const; + }; @@ -133,10 +129,7 @@ struct DriveBitMarker return offset < other.offset; } - unsigned int hash() const - { - return mkhash_add(marker, offset); - } + Hasher hash_acc(Hasher h) const; }; @@ -171,10 +164,7 @@ public: return multiple_ == other.multiple_; } - unsigned int hash() const - { - return multiple_.hash(); - } + Hasher hash_acc(Hasher h) const; }; struct DriveBit @@ -362,35 +352,7 @@ public: return *this; } - unsigned int hash() const - { - unsigned int inner = 0; - switch (type_) - { - case DriveType::NONE: - inner = 0; - break; - case DriveType::CONSTANT: - inner = constant_; - break; - case DriveType::WIRE: - inner = wire_.hash(); - break; - case DriveType::PORT: - inner = port_.hash(); - break; - case DriveType::MARKER: - inner = marker_.hash(); - break; - case DriveType::MULTIPLE: - inner = multiple_.hash(); - break; - default: - log_abort(); - break; - } - return mkhash((unsigned int)type_, inner); - } + Hasher hash_acc(Hasher h) const; bool operator==(const DriveBit &other) const { @@ -511,10 +473,7 @@ struct DriveChunkWire return offset < other.offset; } - unsigned int hash() const - { - return mkhash_add(mkhash(wire->name.hash(), width), offset); - } + Hasher hash_acc(Hasher h) const; explicit operator SigChunk() const { @@ -572,10 +531,7 @@ struct DriveChunkPort return offset < other.offset; } - unsigned int hash() const - { - return mkhash_add(mkhash(mkhash(cell->name.hash(), port.hash()), width), offset); - } + Hasher hash_acc(Hasher h) const; }; @@ -616,10 +572,7 @@ struct DriveChunkMarker return offset < other.offset; } - unsigned int hash() const - { - return mkhash_add(mkhash(marker, width), offset); - } + Hasher hash_acc(Hasher h) const; }; struct DriveChunkMultiple @@ -659,10 +612,7 @@ public: return false; // TODO implement, canonicalize order } - unsigned int hash() const - { - return mkhash(width_, multiple_.hash()); - } + Hasher hash_acc(Hasher h) const; }; struct DriveChunk @@ -913,6 +863,7 @@ public: bool try_append(DriveBit const &bit); bool try_append(DriveChunk const &chunk); +<<<<<<< HEAD unsigned int hash() const { unsigned int inner = 0; @@ -942,6 +893,9 @@ public: } return mkhash((unsigned int)type_, inner); } +======= + Hasher hash_acc(Hasher h) const; +>>>>>>> 898d04260 (hashlib: redo interface for flexibility) bool operator==(const DriveChunk &other) const { @@ -1144,17 +1098,19 @@ public: DriveSpec &operator=(DriveBitMarker const &bit) { return *this = DriveBit(bit); } DriveSpec &operator=(DriveBitMultiple const &bit) { return *this = DriveBit(bit); } - unsigned int hash() const { - if (hash_ != 0) return hash_; - + void updhash() const { + DriveSpec *that = (DriveSpec*)this; pack(); - hash_ = hash_ops>().hash(chunks_); - hash_ |= (hash_ == 0); - return hash_; + that->hash_ = run_hash(chunks_); + that->hash_ |= (that->hash_ == 0); } + Hasher hash_acc(Hasher h) const; + bool operator==(DriveSpec const &other) const { - if (size() != other.size() || hash() != other.hash()) + updhash(); + other.updhash(); + if (size() != other.size() || hash_ != other.hash_) return false; return chunks() == other.chunks(); } @@ -1187,7 +1143,8 @@ private: bool operator==(const DriveBitId &other) const { return id == other.id; } bool operator!=(const DriveBitId &other) const { return id != other.id; } bool operator<(const DriveBitId &other) const { return id < other.id; } - unsigned int hash() const { return id; } + // unsigned int hash() const { return id; } + Hasher hash_acc(Hasher h) const; }; // Essentially a dict> but using less memory // and fewer allocations @@ -1333,6 +1290,133 @@ private: } }; +inline Hasher DriveBitWire::hash_acc(Hasher h) const +{ + h.acc(wire->name); + h.acc(offset); + return h; +} + +inline Hasher DriveBitPort::hash_acc(Hasher h) const +{ + h.acc(cell->name); + h.acc(port); + h.acc(offset); + return h; +} + +inline Hasher DriveBitMarker::hash_acc(Hasher h) const +{ + h.acc(marker); + h.acc(offset); + return h; +} + +inline Hasher DriveBitMultiple::hash_acc(Hasher h) const +{ + h.acc(multiple_); + return h; +} + +inline Hasher DriveBit::hash_acc(Hasher h) const +{ + switch (type_) { + case DriveType::NONE: + h.acc(0); + break; + case DriveType::CONSTANT: + h.acc(constant_); + break; + case DriveType::WIRE: + h.acc(wire_); + break; + case DriveType::PORT: + h.acc(port_); + break; + case DriveType::MARKER: + h.acc(marker_); + break; + case DriveType::MULTIPLE: + h.acc(multiple_); + break; + } + h.acc(type_); + return h; +} + +inline Hasher DriveChunkWire::hash_acc(Hasher h) const +{ + h.acc(wire->name); + h.acc(width); + h.acc(offset); + return h; +} + +inline Hasher DriveChunkPort::hash_acc(Hasher h) const +{ + h.acc(cell->name); + h.acc(port); + h.acc(width); + h.acc(offset); + return h; +} + +inline Hasher DriveChunkMarker::hash_acc(Hasher h) const +{ + h.acc(marker); + h.acc(width); + h.acc(offset); + return h; +} + +inline Hasher DriveChunkMultiple::hash_acc(Hasher h) const +{ + h.acc(width_); + h.acc(multiple_); + return h; +} + +inline Hasher DriveChunk::hash_acc(Hasher h) const +{ + switch (type_) { + case DriveType::NONE: + h.acc(0); + break; + case DriveType::CONSTANT: + h.acc(constant_); + break; + case DriveType::WIRE: + h.acc(wire_); + break; + case DriveType::PORT: + h.acc(port_); + break; + case DriveType::MARKER: + h.acc(marker_); + break; + case DriveType::MULTIPLE: + h.acc(multiple_); + break; + } + h.acc(type_); + return h; +} + +inline Hasher DriveSpec::hash_acc(Hasher h) const +{ + if (hash_ == 0) + updhash(); + + h.acc(hash_); + return h; +} + +inline Hasher DriverMap::DriveBitId::hash_acc(Hasher h) const +{ + h.acc(id); + return h; +} + YOSYS_NAMESPACE_END #endif diff --git a/kernel/functional.h b/kernel/functional.h index 61b303e0b..b80c77be4 100644 --- a/kernel/functional.h +++ b/kernel/functional.h @@ -151,7 +151,7 @@ namespace Functional { // returns the data width of a bitvector sort, errors out for other sorts int data_width() const { return std::get<1>(_v).second; } bool operator==(Sort const& other) const { return _v == other._v; } - unsigned int hash() const { return mkhash(_v); } + Hasher hash_acc(Hasher h) const { h.acc(_v); return h; } }; class IR; class Factory; @@ -225,8 +225,10 @@ namespace Functional { const RTLIL::Const &as_const() const { return std::get(_extra); } std::pair as_idstring_pair() const { return std::get>(_extra); } int as_int() const { return std::get(_extra); } - int hash() const { - return mkhash((unsigned int) _fn, mkhash(_extra)); + Hasher hash_acc(Hasher h) const { + h.acc((unsigned int) _fn); + h.acc(_extra); + return h; } bool operator==(NodeData const &other) const { return _fn == other._fn && _extra == other._extra; diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 859115829..21e4e155b 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -17,27 +17,47 @@ #include #include #include - +#include #include namespace hashlib { +/** + * HASHING + * + * The Hasher knows how to hash 32 and 64-bit integers. That's it. + * In the future, it could be expanded to do vectors with SIMD. + * + * The Hasher doesn't know how to hash common standard containers + * and compositions. However, hashlib provides centralized wrappers. + * + * Hashlib doesn't know how to hash silly Yosys-specific types. + * Hashlib doesn't depend on Yosys and can be used standalone. + * Please don't use hashlib standalone for new projects. + * + * The hash_ops type is now always left to its default value, derived + * from templated functions through SFINAE. Providing custom ops is + * still supported. + * + * HASH TABLES + * + * We implement associative data structures with separate chaining. + * Linked lists use integers into the indirection hashtable array + * instead of pointers. + */ + +// TODO describe how comparison hashes are special +// TODO draw the line between generic and hash function specific code + const int hashtable_size_trigger = 2; const int hashtable_size_factor = 3; -// The XOR version of DJB2 -inline unsigned int mkhash(unsigned int a, unsigned int b) { - return ((a << 5) + a) ^ b; -} +#define DJB2_BROKEN_SIZE -// traditionally 5381 is used as starting value for the djb2 hash -const unsigned int mkhash_init = 5381; +#ifdef DJB2_BROKEN_SIZE -// The ADD version of DJB2 -// (use this version for cache locality in b) -inline unsigned int mkhash_add(unsigned int a, unsigned int b) { - return ((a << 5) + a) + b; -} +template +struct hash_ops; inline unsigned int mkhash_xorshift(unsigned int a) { if (sizeof(a) == 4) { @@ -53,62 +73,76 @@ inline unsigned int mkhash_xorshift(unsigned int a) { return a; } -template struct hash_ops { +class Hasher { + public: //TODO + using hash_t = uint32_t; + + Hasher() { + // traditionally 5381 is used as starting value for the djb2 hash + state = 5381; + } + + private: + uint32_t state; + // The XOR version of DJB2 + [[nodiscard]] + static uint32_t mkhash(uint32_t a, uint32_t b) { + return ((a << 5) + a) ^ b; + } + public: + void hash32(uint32_t i) { + state = mkhash(i, state); + return; + } + void hash64(uint64_t i) { + state = mkhash((uint32_t)(i % (1ULL << 32ULL)), state); + state = mkhash((uint32_t)(i >> 32ULL), state); + return; + } + hash_t yield() { + return (hash_t)state; + } + + template + void acc(T t) { + *this = hash_ops::hash_acc(t, *this); + } + + void commutative_acc(uint32_t t) { + state ^= t; + } + +}; +#endif + +template +struct hash_ops { static inline bool cmp(const T &a, const T &b) { return a == b; } - static inline unsigned int hash(const T &a) { - return a.hash(); - } -}; - -struct hash_int_ops { - template - static inline bool cmp(T a, T b) { - return a == b; - } -}; - -template<> struct hash_ops : hash_int_ops -{ - static inline unsigned int hash(bool a) { - return a ? 1 : 0; - } -}; -template<> struct hash_ops : hash_int_ops -{ - static inline unsigned int hash(int32_t a) { - return a; - } -}; -template<> struct hash_ops : hash_int_ops -{ - static inline unsigned int hash(int64_t a) { - return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); - } -}; -template<> struct hash_ops : hash_int_ops -{ - static inline unsigned int hash(uint32_t a) { - return a; - } -}; -template<> struct hash_ops : hash_int_ops -{ - static inline unsigned int hash(uint64_t a) { - return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); - } -}; - -template<> struct hash_ops { - static inline bool cmp(const std::string &a, const std::string &b) { - return a == b; - } - static inline unsigned int hash(const std::string &a) { - unsigned int v = 0; - for (auto c : a) - v = mkhash(v, c); - return v; + static inline Hasher hash_acc(const T &a, Hasher h) { + if constexpr (std::is_same_v) { + h.hash32(a ? 1 : 0); + return h; + } else if constexpr (std::is_integral_v) { + static_assert(sizeof(T) <= sizeof(uint64_t)); + if (sizeof(T) == sizeof(uint64_t)) + h.hash64(a); + else + h.hash32(a); + return h; + } else if constexpr (std::is_enum_v) { + using u_type = std::underlying_type_t; + return hash_ops::hash_acc((u_type) a, h); + } else if constexpr (std::is_pointer_v) { + return hash_ops::hash_acc((uintptr_t) a, h); + } else if constexpr (std::is_same_v) { + for (auto c : a) + h.hash32(c); + return h; + } else { + return a.hash_acc(h); + } } }; @@ -116,8 +150,10 @@ template struct hash_ops> { static inline bool cmp(std::pair a, std::pair b) { return a == b; } - static inline unsigned int hash(std::pair a) { - return mkhash(hash_ops

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

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

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

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

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

::hash_into(a.first, h); + h = hash_ops::hash_into(a.second, h); return h; } }; @@ -204,14 +204,14 @@ template struct hash_ops> { return a == b; } template - static inline typename std::enable_if::type hash_eat(std::tuple, Hasher h) { + static inline typename std::enable_if::type hash_into(std::tuple, Hasher h) { return h; } template - static inline typename std::enable_if::type hash_eat(std::tuple a, Hasher h) { + static inline typename std::enable_if::type hash_into(std::tuple a, Hasher h) { typedef hash_ops>::type> element_ops_t; - h = hash_eat(a, h); - h = element_ops_t::hash_eat(std::get(a), h); + h = hash_into(a, h); + h = element_ops_t::hash_into(std::get(a), h); return h; } }; @@ -220,7 +220,7 @@ template struct hash_ops> { static inline bool cmp(std::vector a, std::vector b) { return a == b; } - static inline Hasher hash_eat(std::vector a, Hasher h) { + static inline Hasher hash_into(std::vector a, Hasher h) { h.eat(a.size()); for (auto k : a) h.eat(k); @@ -232,9 +232,9 @@ template struct hash_ops> { static inline bool cmp(std::array a, std::array b) { return a == b; } - static inline Hasher hash_eat(std::array a, Hasher h) { + static inline Hasher hash_into(std::array a, Hasher h) { for (const auto& k : a) - h = hash_ops::hash_eat(k, h); + h = hash_ops::hash_into(k, h); return h; } }; @@ -246,7 +246,7 @@ struct hash_cstr_ops { return false; return true; } - static inline Hasher hash_eat(const char *a, Hasher h) { + static inline Hasher hash_into(const char *a, Hasher h) { while (*a) h.hash32(*(a++)); return h; @@ -259,8 +259,8 @@ struct hash_ptr_ops { static inline bool cmp(const void *a, const void *b) { return a == b; } - static inline Hasher hash_eat(const void *a, Hasher h) { - return hash_ops::hash_eat((uintptr_t)a, h); + static inline Hasher hash_into(const void *a, Hasher h) { + return hash_ops::hash_into((uintptr_t)a, h); } }; @@ -269,8 +269,8 @@ struct hash_obj_ops { return a == b; } template - static inline Hasher hash_eat(const T *a, Hasher h) { - return a ? a->hash_eat(h) : h; + static inline Hasher hash_into(const T *a, Hasher h) { + return a ? a->hash_into(h) : h; } }; /** @@ -297,7 +297,7 @@ template<> struct hash_ops { static inline bool cmp(std::monostate a, std::monostate b) { return a == b; } - static inline Hasher hash_eat(std::monostate, Hasher h) { + static inline Hasher hash_into(std::monostate, Hasher h) { return h; } }; @@ -306,7 +306,7 @@ template struct hash_ops> { static inline bool cmp(std::variant a, std::variant b) { return a == b; } - static inline Hasher hash_eat(std::variant a, Hasher h) { + static inline Hasher hash_into(std::variant a, Hasher h) { std::visit([& h](const auto &v) { h.eat(v); }, a); h.eat(a.index()); return h; @@ -317,7 +317,7 @@ template struct hash_ops> { static inline bool cmp(std::optional a, std::optional b) { return a == b; } - static inline Hasher hash_eat(std::optional a, Hasher h) { + static inline Hasher hash_into(std::optional a, Hasher h) { if(a.has_value()) h.eat(*a); else @@ -790,7 +790,7 @@ public: return !operator==(other); } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(entries.size()); for (auto &it : entries) { Hasher entry_hash; @@ -1160,7 +1160,7 @@ public: return !operator==(other); } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(entries.size()); for (auto &it : entries) { h.commutative_eat(ops.hash(it.udata).yield()); diff --git a/kernel/modtools.h b/kernel/modtools.h index fce22d857..0ed858e37 100644 --- a/kernel/modtools.h +++ b/kernel/modtools.h @@ -48,7 +48,7 @@ struct ModIndex : public RTLIL::Monitor return cell == other.cell && port == other.port && offset == other.offset; } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(cell->name); h.eat(port); h.eat(offset); @@ -324,7 +324,7 @@ struct ModWalker return cell == other.cell && port == other.port && offset == other.offset; } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(cell->name); h.eat(port); h.eat(offset); diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 2b3d274a2..0f4bec7b0 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -362,7 +362,7 @@ struct RTLIL::IdString *this = IdString(); } - Hasher hash_eat(Hasher h) const { return hash_ops::hash_eat(index_, h); } + Hasher hash_into(Hasher h) const { return hash_ops::hash_into(index_, h); } Hasher hash_top() const { Hasher h; @@ -815,7 +815,7 @@ public: bv.resize(width, bv.empty() ? RTLIL::State::Sx : bv.back()); } - inline Hasher hash_eat(Hasher h) const { + inline Hasher hash_into(Hasher h) const { // TODO hash size for (auto b : *this) h.eat(b); @@ -908,7 +908,7 @@ struct RTLIL::SigBit bool operator <(const RTLIL::SigBit &other) const; bool operator ==(const RTLIL::SigBit &other) const; bool operator !=(const RTLIL::SigBit &other) const; - Hasher hash_eat(Hasher h) const; + Hasher hash_into(Hasher h) const; Hasher hash_top() const; }; @@ -1115,7 +1115,7 @@ public: operator std::vector() const { return bits(); } const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; } - Hasher hash_eat(Hasher h) const { if (!hash_) updhash(); h.eat(hash_); return h; } + Hasher hash_into(Hasher h) const { if (!hash_) updhash(); h.eat(hash_); return h; } #ifndef NDEBUG void check(Module *mod = nullptr) const; @@ -1157,7 +1157,7 @@ struct RTLIL::Selection struct RTLIL::Monitor { Hasher::hash_t hashidx_; - Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } + Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } Monitor() { static unsigned int hashidx_count = 123456789; @@ -1180,7 +1180,7 @@ struct define_map_t; struct RTLIL::Design { Hasher::hash_t hashidx_; - Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } + Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } pool monitors; dict scratchpad; @@ -1285,7 +1285,7 @@ struct RTLIL::Design struct RTLIL::Module : public RTLIL::AttrObject { Hasher::hash_t hashidx_; - Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } + Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } protected: void add(RTLIL::Wire *wire); @@ -1640,7 +1640,7 @@ void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire); struct RTLIL::Wire : public RTLIL::AttrObject { Hasher::hash_t hashidx_; - Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } + Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } protected: // use module->addWire() and module->remove() to create or destroy wires @@ -1679,7 +1679,7 @@ inline int GetSize(RTLIL::Wire *wire) { struct RTLIL::Memory : public RTLIL::AttrObject { Hasher::hash_t hashidx_; - Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } + Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } Memory(); @@ -1694,7 +1694,7 @@ struct RTLIL::Memory : public RTLIL::AttrObject struct RTLIL::Cell : public RTLIL::AttrObject { Hasher::hash_t hashidx_; - Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } + Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } protected: // use module->addCell() and module->remove() to create or destroy cells @@ -1804,7 +1804,7 @@ struct RTLIL::SyncRule struct RTLIL::Process : public RTLIL::AttrObject { Hasher::hash_t hashidx_; - Hasher hash_eat(Hasher h) const { h.eat(hashidx_); return h; } + Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } protected: // use module->addProcess() and module->remove() to create or destroy processes @@ -1848,7 +1848,7 @@ inline bool RTLIL::SigBit::operator!=(const RTLIL::SigBit &other) const { return (wire != other.wire) || (wire ? (offset != other.offset) : (data != other.data)); } -inline Hasher RTLIL::SigBit::hash_eat(Hasher h) const { +inline Hasher RTLIL::SigBit::hash_into(Hasher h) const { if (wire) { h.eat(offset); h.eat(wire->name); diff --git a/kernel/scopeinfo.h b/kernel/scopeinfo.h index 3c9ca69b6..f3ae0d7b6 100644 --- a/kernel/scopeinfo.h +++ b/kernel/scopeinfo.h @@ -169,7 +169,7 @@ public: return !(*this == other); } - Hasher hash_acc(Hasher h) const + Hasher hash_into(Hasher h) const { h.eat(scope_name); h.eat(target); @@ -325,7 +325,7 @@ struct ModuleItem { Cell *cell() const { return type == Type::Cell ? static_cast(ptr) : nullptr; } bool operator==(const ModuleItem &other) const { return ptr == other.ptr && type == other.type; } - Hasher hash_eat(Hasher h) const { h.eat(ptr); return h; } + Hasher hash_into(Hasher h) const { h.eat(ptr); return h; } }; static inline void log_dump_val_worker(typename IdTree::Cursor cursor ) { log("%p %s", cursor.target, log_id(cursor.scope_name)); } diff --git a/kernel/sigtools.h b/kernel/sigtools.h index c827807aa..a22685ee2 100644 --- a/kernel/sigtools.h +++ b/kernel/sigtools.h @@ -29,7 +29,7 @@ struct SigPool struct bitDef_t : public std::pair { bitDef_t() : std::pair(NULL, 0) { } bitDef_t(const RTLIL::SigBit &bit) : std::pair(bit.wire, bit.offset) { } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(first->name); h.eat(second); return h; @@ -147,7 +147,7 @@ struct SigSet struct bitDef_t : public std::pair { bitDef_t() : std::pair(NULL, 0) { } bitDef_t(const RTLIL::SigBit &bit) : std::pair(bit.wire, bit.offset) { } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(first->name); h.eat(second); return h; diff --git a/kernel/timinginfo.h b/kernel/timinginfo.h index e294d29a7..677bbecb8 100644 --- a/kernel/timinginfo.h +++ b/kernel/timinginfo.h @@ -44,7 +44,7 @@ struct TimingInfo return {}; return port[offset]; } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(name); h.eat(offset); return h; @@ -56,7 +56,7 @@ struct TimingInfo BitBit(const NameBit &first, const NameBit &second) : first(first), second(second) {} BitBit(const SigBit &first, const SigBit &second) : first(first), second(second) {} bool operator==(const BitBit& bb) const { return bb.first == first && bb.second == second; } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(first); h.eat(second); return h; diff --git a/kernel/yosys_common.h b/kernel/yosys_common.h index b194718f1..e0bd91ec8 100644 --- a/kernel/yosys_common.h +++ b/kernel/yosys_common.h @@ -171,7 +171,7 @@ struct shared_str { const char *c_str() const { return content->c_str(); } const string &str() const { return *content; } bool operator==(const shared_str &other) const { return *content == *other.content; } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(*content); return h; } diff --git a/kernel/yw.h b/kernel/yw.h index e16d49866..34546d1e2 100644 --- a/kernel/yw.h +++ b/kernel/yw.h @@ -35,7 +35,7 @@ struct IdPath : public std::vector bool has_address() const { int tmp; return get_address(tmp); }; bool get_address(int &addr) const; - Hasher hash_eat(Hasher h) const { h.eat(*this); return h; } + Hasher hash_into(Hasher h) const { h.eat(*this); return h; } }; struct WitnessHierarchyItem { diff --git a/passes/cmds/dft_tag.cc b/passes/cmds/dft_tag.cc index 2a5fb690e..cecab4d61 100644 --- a/passes/cmds/dft_tag.cc +++ b/passes/cmds/dft_tag.cc @@ -47,7 +47,7 @@ struct DftTagWorker { bool operator<(const tag_set &other) const { return index < other.index; } bool operator==(const tag_set &other) const { return index == other.index; } - Hasher hash_eat(Hasher h) const { h.eat(index); return h; } + Hasher hash_into(Hasher h) const { h.eat(index); return h; } bool empty() const { return index == 0; } }; diff --git a/passes/cmds/example_dt.cc b/passes/cmds/example_dt.cc index 7cd1d2f24..5f5246de6 100644 --- a/passes/cmds/example_dt.cc +++ b/passes/cmds/example_dt.cc @@ -52,7 +52,7 @@ struct ExampleDtPass : public Pass return name == other.name && parameters == other.parameters; } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(name); h.eat(parameters); return h; diff --git a/passes/equiv/equiv_struct.cc b/passes/equiv/equiv_struct.cc index 774c5a1a6..195cb3424 100644 --- a/passes/equiv/equiv_struct.cc +++ b/passes/equiv/equiv_struct.cc @@ -46,7 +46,7 @@ struct EquivStructWorker parameters == other.parameters && port_sizes == other.port_sizes; } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(type); h.eat(parameters); h.eat(port_sizes); diff --git a/passes/proc/proc_dlatch.cc b/passes/proc/proc_dlatch.cc index 6b579b4e4..2e41afd09 100644 --- a/passes/proc/proc_dlatch.cc +++ b/passes/proc/proc_dlatch.cc @@ -127,7 +127,7 @@ struct proc_dlatch_db_t return signal == other.signal && match == other.match && children == other.children; } - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { h.eat(signal); h.eat(match); h.eat(children); diff --git a/passes/sat/recover_names.cc b/passes/sat/recover_names.cc index a84380cbf..c18beafa1 100644 --- a/passes/sat/recover_names.cc +++ b/passes/sat/recover_names.cc @@ -46,7 +46,7 @@ struct IdBit { bool operator==(const IdBit &other) const { return name == other.name && bit == other.bit; }; bool operator!=(const IdBit &other) const { return name != other.name || bit != other.bit; }; - Hasher hash_eat(Hasher h) const + Hasher hash_into(Hasher h) const { h.eat(name); h.eat(bit); @@ -64,7 +64,7 @@ struct InvBit { bool operator==(const InvBit &other) const { return bit == other.bit && inverted == other.inverted; }; bool operator!=(const InvBit &other) const { return bit != other.bit || inverted != other.inverted; }; - Hasher hash_eat(Hasher h) const + Hasher hash_into(Hasher h) const { h.eat(bit); h.eat(inverted); diff --git a/passes/techmap/clockgate.cc b/passes/techmap/clockgate.cc index bfd4c8a97..bdfb94170 100644 --- a/passes/techmap/clockgate.cc +++ b/passes/techmap/clockgate.cc @@ -233,7 +233,7 @@ struct ClockgatePass : public Pass { SigBit ce_bit; bool pol_clk; bool pol_ce; - Hasher hash_eat(Hasher h) const { + Hasher hash_into(Hasher h) const { auto t = std::make_tuple(clk_bit, ce_bit, pol_clk, pol_ce); h.eat(t); return h; diff --git a/passes/techmap/flowmap.cc b/passes/techmap/flowmap.cc index bfee38999..00d5369e4 100644 --- a/passes/techmap/flowmap.cc +++ b/passes/techmap/flowmap.cc @@ -250,7 +250,7 @@ struct FlowGraph { return !(*this == other); } - Hasher hash_eat(Hasher h) const + Hasher hash_into(Hasher h) const { std::pair p = {node, is_bottom}; h.eat(p); diff --git a/techlibs/quicklogic/ql_dsp_simd.cc b/techlibs/quicklogic/ql_dsp_simd.cc index 162f0c2d6..bda7fb3bd 100644 --- a/techlibs/quicklogic/ql_dsp_simd.cc +++ b/techlibs/quicklogic/ql_dsp_simd.cc @@ -53,7 +53,7 @@ struct QlDspSimdPass : public Pass { DspConfig(const DspConfig &ref) = default; DspConfig(DspConfig &&ref) = default; - Hasher hash_eat(Hasher h) const { h.eat(connections); return h; } + Hasher hash_into(Hasher h) const { h.eat(connections); return h; } bool operator==(const DspConfig &ref) const { return connections == ref.connections; } }; From ed70038aa1472197f71f0a69835a830a5970fff0 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 20 Nov 2024 12:11:37 +0100 Subject: [PATCH 36/83] hashlib: fixes from jix --- kernel/drivertools.h | 11 +++++------ kernel/hashlib.h | 14 ++++---------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/kernel/drivertools.h b/kernel/drivertools.h index 19c9c2e34..e584f4d39 100644 --- a/kernel/drivertools.h +++ b/kernel/drivertools.h @@ -1067,10 +1067,11 @@ public: DriveSpec &operator=(DriveBitMultiple const &bit) { return *this = DriveBit(bit); } void updhash() const { - DriveSpec *that = (DriveSpec*)this; + if (hash_ != 0) + return; pack(); - that->hash_ = run_hash(chunks_); - that->hash_ |= (that->hash_ == 0); + hash_ = run_hash(chunks_); + hash_ |= (hash_ == 0); } Hasher hash_into(Hasher h) const; @@ -1372,9 +1373,7 @@ inline Hasher DriveChunk::hash_into(Hasher h) const inline Hasher DriveSpec::hash_into(Hasher h) const { - if (hash_ == 0) - updhash(); - + updhash(); h.eat(hash_); return h; } diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 5b1a2a877..0e712a2a3 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -116,7 +116,7 @@ private: return; } void hash64(uint64_t i) { - state = djb2_xor((uint32_t)(i % (1ULL << 32ULL)), state); + state = djb2_xor((uint32_t)(i & 0xFFFFFFFFULL), state); state = djb2_xor((uint32_t)(i >> 32ULL), state); state = mkhash_xorshift(fudge ^ state); return; @@ -163,10 +163,7 @@ struct hash_ops { return a == b; } static inline Hasher hash_into(const T &a, Hasher h) { - if constexpr (std::is_same_v) { - h.hash32(a ? 1 : 0); - return h; - } else if constexpr (std::is_integral_v) { + if constexpr (std::is_integral_v) { static_assert(sizeof(T) <= sizeof(uint64_t)); if (sizeof(T) == sizeof(uint64_t)) h.hash64(a); @@ -221,7 +218,7 @@ template struct hash_ops> { return a == b; } static inline Hasher hash_into(std::vector a, Hasher h) { - h.eat(a.size()); + h.eat((uint32_t)a.size()); for (auto k : a) h.eat(k); return h; @@ -241,10 +238,7 @@ template struct hash_ops> { struct hash_cstr_ops { static inline bool cmp(const char *a, const char *b) { - for (int i = 0; a[i] || b[i]; i++) - if (a[i] != b[i]) - return false; - return true; + return strcmp(a, b) == 0; } static inline Hasher hash_into(const char *a, Hasher h) { while (*a) From 026e9dae9d7a2c2e4ce90a6125c0d57922f6a8de Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 20 Nov 2024 17:06:49 +0100 Subject: [PATCH 37/83] hashlib: fixes from jix --- kernel/drivertools.h | 1 - kernel/hashlib.h | 10 +++++++--- kernel/modtools.h | 3 --- kernel/rtlil.h | 16 ++++++++-------- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/kernel/drivertools.h b/kernel/drivertools.h index e584f4d39..23eba9f1c 100644 --- a/kernel/drivertools.h +++ b/kernel/drivertools.h @@ -1112,7 +1112,6 @@ private: bool operator==(const DriveBitId &other) const { return id == other.id; } bool operator!=(const DriveBitId &other) const { return id != other.id; } bool operator<(const DriveBitId &other) const { return id < other.id; } - // unsigned int hash() const { return id; } Hasher hash_into(Hasher h) const; }; // Essentially a dict> but using less memory diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 0e712a2a3..6927702e1 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -264,7 +264,11 @@ struct hash_obj_ops { } template static inline Hasher hash_into(const T *a, Hasher h) { - return a ? a->hash_into(h) : h; + if (a) + a->hash_into(h); + else + h.eat(0); + return h; } }; /** @@ -785,13 +789,13 @@ public: } Hasher hash_into(Hasher h) const { - h.eat(entries.size()); for (auto &it : entries) { Hasher entry_hash; entry_hash.eat(it.udata.first); entry_hash.eat(it.udata.second); h.commutative_eat(entry_hash.yield()); } + h.eat(entries.size()); return h; } @@ -1155,10 +1159,10 @@ public: } Hasher hash_into(Hasher h) const { - h.eat(entries.size()); for (auto &it : entries) { h.commutative_eat(ops.hash(it.udata).yield()); } + h.eat(entries.size()); return h; } diff --git a/kernel/modtools.h b/kernel/modtools.h index 0ed858e37..921df304c 100644 --- a/kernel/modtools.h +++ b/kernel/modtools.h @@ -60,8 +60,6 @@ struct ModIndex : public RTLIL::Monitor { bool is_input, is_output; pool ports; - // SigBitInfo() : SigBitInfo{} {} - // SigBitInfo& operator=(const SigBitInfo&) = default; SigBitInfo() : is_input(false), is_output(false) { } @@ -310,7 +308,6 @@ struct ModWalker RTLIL::IdString port; int offset; PortBit(Cell* c, IdString p, int o) : cell(c), port(p), offset(o) {} - // PortBit& operator=(const PortBit&) = default; bool operator<(const PortBit &other) const { if (cell != other.cell) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 0f4bec7b0..330af649f 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -408,8 +408,14 @@ namespace hashlib { }; }; -// TODO deprecate this +/** + * How to not use these methods: + * 1. if(celltype.in({...})) -> if(celltype.in(...)) + * 2. pool p; ... a.in(p) -> (bool)p.count(a) + */ +[[deprecated]] inline bool RTLIL::IdString::in(const pool &rhs) const { return rhs.count(*this) != 0; } +[[deprecated]] inline bool RTLIL::IdString::in(const pool &&rhs) const { return rhs.count(*this) != 0; } namespace RTLIL { @@ -816,7 +822,7 @@ public: } inline Hasher hash_into(Hasher h) const { - // TODO hash size + h.eat(size()); for (auto b : *this) h.eat(b); return h; @@ -1003,12 +1009,6 @@ public: SigSpec(const std::set &bits); explicit SigSpec(bool bit); - [[deprecated]] - size_t get_hash() const { - log_assert(false && "deprecated"); - return 0; - } - inline const std::vector &chunks() const { pack(); return chunks_; } inline const std::vector &bits() const { inline_unpack(); return bits_; } From 281e474d45252c03499e25a059d250304badf19b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 00:22:04 +0000 Subject: [PATCH 38/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7281dec7b..0614235ca 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.48+5 +YOSYS_VER := 0.48+40 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From a6bd8ff3e52960eeaa7e10e52e4abe7f75862088 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 19 Dec 2024 11:47:34 +0100 Subject: [PATCH 39/83] yw: fix unintensional recursion in hash_into --- kernel/yw.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/yw.h b/kernel/yw.h index 34546d1e2..3c3b4fd40 100644 --- a/kernel/yw.h +++ b/kernel/yw.h @@ -35,7 +35,10 @@ struct IdPath : public std::vector bool has_address() const { int tmp; return get_address(tmp); }; bool get_address(int &addr) const; - Hasher hash_into(Hasher h) const { h.eat(*this); return h; } + Hasher hash_into(Hasher h) const { + h.eat(static_cast&&>(*this)); + return h; + } }; struct WitnessHierarchyItem { From cea53262290c9cdc5ec3da32f46bec4fc87dc9e8 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 19 Dec 2024 15:55:51 +0100 Subject: [PATCH 40/83] yosys_common: fix gcc warning in #error directive --- kernel/yosys_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/yosys_common.h b/kernel/yosys_common.h index e0bd91ec8..25a97a8dd 100644 --- a/kernel/yosys_common.h +++ b/kernel/yosys_common.h @@ -134,7 +134,7 @@ YOSYS_NAMESPACE_BEGIN // Note: All headers included in hashlib.h must be included // outside of YOSYS_NAMESPACE before this or bad things will happen. #ifdef HASHLIB_H -# error You've probably included hashlib.h under two namespace paths. Bad idea. +# error "You've probably included hashlib.h under two namespace paths. Bad idea." #else # include "kernel/hashlib.h" # undef HASHLIB_H From 8acc77c1e0e7c67ab174875556ce6743faf9efae Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 00:21:02 +0000 Subject: [PATCH 41/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0614235ca..9d96f37ab 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.48+40 +YOSYS_VER := 0.48+45 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 1ef4c7f56553e1042f1878a021f37f60b0fc4acb Mon Sep 17 00:00:00 2001 From: Catherine Date: Wed, 25 Dec 2024 04:59:02 +0000 Subject: [PATCH 42/83] yosys-smtbmc: add cvc5 to help text. --- backends/smt2/smtio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py index 5fc3ab5a4..2bc7daddc 100644 --- a/backends/smt2/smtio.py +++ b/backends/smt2/smtio.py @@ -1208,7 +1208,7 @@ class SmtOpts: def helpmsg(self): return """ -s - set SMT solver: z3, yices, boolector, bitwuzla, cvc4, mathsat, dummy + set SMT solver: z3, yices, boolector, bitwuzla, cvc4, cvc5, mathsat, dummy default: yices -S From cbb95cb5172a084cb7221007b4cdb2326ca3abf9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 26 Dec 2024 00:20:44 +0000 Subject: [PATCH 43/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9d96f37ab..c8c68669b 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.48+45 +YOSYS_VER := 0.48+47 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 1ae0d8432f306edf9f05fc960794046e3d397f88 Mon Sep 17 00:00:00 2001 From: mikesinouye Date: Thu, 2 Jan 2025 08:59:11 -0800 Subject: [PATCH 44/83] Approximately double the max hash table size --- kernel/hashlib.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 6927702e1..9aac70f2a 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -324,10 +324,10 @@ template struct hash_ops> { } }; -inline int hashtable_size(int min_size) +inline unsigned int hashtable_size(unsigned int min_size) { // Primes as generated by https://oeis.org/A175953 - static std::vector zero_and_some_primes = { + static std::vector zero_and_some_primes = { 0, 23, 29, 37, 47, 59, 79, 101, 127, 163, 211, 269, 337, 431, 541, 677, 853, 1069, 1361, 1709, 2137, 2677, 3347, 4201, 5261, 6577, 8231, 10289, 12889, 16127, 20161, 25219, 31531, 39419, 49277, 61603, 77017, 96281, @@ -337,13 +337,13 @@ inline int hashtable_size(int min_size) 25499291, 31874149, 39842687, 49803361, 62254207, 77817767, 97272239, 121590311, 151987889, 189984863, 237481091, 296851369, 371064217, 463830313, 579787991, 724735009, 905918777, 1132398479, 1415498113, - 1769372713 + 1769372713, 2211715897, 2764644871, 2764644887, 3455806139 }; for (auto p : zero_and_some_primes) if (p >= min_size) return p; - if (sizeof(int) == 4) + if (sizeof(unsigned int) == 4) throw std::length_error("hash table exceeded maximum size.\nDesign is likely too large for yosys to handle, if possible try not to flatten the design."); for (auto p : zero_and_some_primes) From de9cb5a60c041447e7e85f2cbfb1d8911f0bda44 Mon Sep 17 00:00:00 2001 From: mikesinouye Date: Thu, 2 Jan 2025 11:05:30 -0800 Subject: [PATCH 45/83] Remove spurious prime --- kernel/hashlib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 9aac70f2a..188b176b4 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -337,7 +337,7 @@ inline unsigned int hashtable_size(unsigned int min_size) 25499291, 31874149, 39842687, 49803361, 62254207, 77817767, 97272239, 121590311, 151987889, 189984863, 237481091, 296851369, 371064217, 463830313, 579787991, 724735009, 905918777, 1132398479, 1415498113, - 1769372713, 2211715897, 2764644871, 2764644887, 3455806139 + 1769372713, 2211715897, 2764644887, 3455806139 }; for (auto p : zero_and_some_primes) From be351886a564c841f171d782d84bf3b297b9376d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Fri, 3 Jan 2025 12:54:34 +0100 Subject: [PATCH 46/83] wreduce: Adjust naming and comments --- passes/opt/wreduce.cc | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 9c0fcc7e1..5b3b1edc8 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -308,7 +308,8 @@ struct WreduceWorker bool port_a_signed = false; bool port_b_signed = false; - // Under certain conditions we are free to choose the signedness of the operands + // For some operations if the output is no wider than either of the inputs + // we are free to choose the signedness of the operands if (cell->type.in(ID($mul), ID($add), ID($sub)) && max_port_a_size == GetSize(sig) && max_port_b_size == GetSize(sig)) { @@ -318,16 +319,16 @@ struct WreduceWorker sig_a.extend_u0(max_port_a_size); sig_b.extend_u0(max_port_b_size); - int signed_size, unsigned_size; + int signed_cost, unsigned_cost; if (cell->type == ID($mul)) { - signed_size = reduced_opsize(sig_a, true) * reduced_opsize(sig_b, true); - unsigned_size = reduced_opsize(sig_a, false) * reduced_opsize(sig_b, false); + signed_cost = reduced_opsize(sig_a, true) * reduced_opsize(sig_b, true); + unsigned_cost = reduced_opsize(sig_a, false) * reduced_opsize(sig_b, false); } else { - signed_size = max(reduced_opsize(sig_a, true), reduced_opsize(sig_b, true)); - unsigned_size = max(reduced_opsize(sig_a, false), reduced_opsize(sig_b, false)); + signed_cost = max(reduced_opsize(sig_a, true), reduced_opsize(sig_b, true)); + unsigned_cost = max(reduced_opsize(sig_a, false), reduced_opsize(sig_b, false)); } - if (!port_a_signed && !port_b_signed && signed_size < unsigned_size) { + if (!port_a_signed && !port_b_signed && signed_cost < unsigned_cost) { log("Converting cell %s.%s (%s) from unsigned to signed.\n", log_id(module), log_id(cell), log_id(cell->type)); cell->setParam(ID::A_SIGNED, 1); @@ -335,7 +336,7 @@ struct WreduceWorker port_a_signed = true; port_b_signed = true; did_something = true; - } else if (port_a_signed && port_b_signed && unsigned_size < signed_size) { + } else if (port_a_signed && port_b_signed && unsigned_cost < signed_cost) { log("Converting cell %s.%s (%s) from signed to unsigned.\n", log_id(module), log_id(cell), log_id(cell->type)); cell->setParam(ID::A_SIGNED, 0); From 17a53b83852886654a781eb9238e528d9c52484d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 4 Jan 2025 00:20:29 +0000 Subject: [PATCH 47/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c8c68669b..6f5fec6a2 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.48+47 +YOSYS_VER := 0.48+51 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 9e039095e9fe25ef49a5993ab6b9699c008d8325 Mon Sep 17 00:00:00 2001 From: KrystalDelusion <93062060+KrystalDelusion@users.noreply.github.com> Date: Mon, 6 Jan 2025 11:08:00 +1300 Subject: [PATCH 48/83] Docs: Remove restructure note It's been almost a year since the restructure, so it's not recent anymore and doesn't need to link back to the old version. --- docs/source/index.rst | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index ab1742424..61dc114ef 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -7,17 +7,6 @@ see :doc:`/introduction`. For a quick guide on how to get started using Yosys, check out :doc:`/getting_started/index`. For the complete list of commands available, go to :ref:`commandindex`. -.. note:: - - This documentation recently went through a major restructure. If you're - looking for something from the previous version and can't find it here, - please `let us know`_. Documentation from before the restructure can still - be found by switching to `version 0.36`_ or earlier. Note that the previous - theme does not include a version switcher. - -.. _let us know: https://github.com/YosysHQ/yosys/issues/new/choose -.. _version 0.36: https://yosyshq.readthedocs.io/projects/yosys/en/0.36/ - .. todo:: look into command ref improvements - Search bar with live drop down suggestions for matching on title / From d37449605d1d66279f81cbe71dbf2e8ec4937215 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 7 Jan 2025 00:21:35 +0000 Subject: [PATCH 49/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6f5fec6a2..c31fc2626 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.48+51 +YOSYS_VER := 0.48+57 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 1836a571c992ea2981325f8979028b418eca247b Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 7 Jan 2025 19:25:15 +0100 Subject: [PATCH 50/83] share: fix misleading log message --- passes/opt/share.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/passes/opt/share.cc b/passes/opt/share.cc index 1408c512a..a4c17795c 100644 --- a/passes/opt/share.cc +++ b/passes/opt/share.cc @@ -1255,7 +1255,6 @@ struct ShareWorker qcsat.max_cell_count = 100; } - pool sat_cells; std::set bits_queue; std::vector cell_active, other_cell_active; @@ -1298,8 +1297,8 @@ struct ShareWorker qcsat.ez->assume(qcsat.ez->AND(sub1, sub2)); - log(" Size of SAT problem: %d cells, %d variables, %d clauses\n", - GetSize(sat_cells), qcsat.ez->numCnfVariables(), qcsat.ez->numCnfClauses()); + log(" Size of SAT problem: %d variables, %d clauses\n", + qcsat.ez->numCnfVariables(), qcsat.ez->numCnfClauses()); if (qcsat.ez->solve(sat_model, sat_model_values)) { log(" According to the SAT solver this pair of cells can not be shared.\n"); From 652a1b98066bf6eb2e39098e896d2636ddd41090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Fri, 13 Dec 2024 18:10:10 +0100 Subject: [PATCH 51/83] macc: Stop using the B port The B port is for single-bit summands. These can just as well be represented as an additional summand on the A port (which supports summands of arbitrary width). An upcoming `$macc_v2` cell won't be special-casing single-bit summands in any way. In preparation, make the following changes: * remove the `bit_ports` field from the `Macc` helper (instead add any single-bit summands to `ports` next to other summands) * leave `B` empty on cells emitted from `Macc::to_cell` --- Makefile | 1 + kernel/consteval.h | 3 -- kernel/macc.h | 32 ++++-------------- kernel/satgen.cc | 7 ---- passes/opt/share.cc | 2 +- passes/techmap/alumacc.cc | 2 +- passes/techmap/maccmap.cc | 24 ++++++++++---- passes/tests/test_cell.cc | 13 ++++---- tests/alumacc/macc_b_port_compat.ys | 50 +++++++++++++++++++++++++++++ tests/alumacc/run-test.sh | 6 ++++ 10 files changed, 89 insertions(+), 51 deletions(-) create mode 100644 tests/alumacc/macc_b_port_compat.ys create mode 100644 tests/alumacc/run-test.sh diff --git a/Makefile b/Makefile index 0614235ca..59f6652ca 100644 --- a/Makefile +++ b/Makefile @@ -869,6 +869,7 @@ endif SH_ABC_TEST_DIRS = SH_ABC_TEST_DIRS += tests/memories SH_ABC_TEST_DIRS += tests/aiger +SH_ABC_TEST_DIRS += tests/alumacc # seed-tests/ is a dummy string, not a directory .PHONY: seed-tests diff --git a/kernel/consteval.h b/kernel/consteval.h index 73d05f0b3..331d8f128 100644 --- a/kernel/consteval.h +++ b/kernel/consteval.h @@ -315,9 +315,6 @@ struct ConstEval Macc macc; macc.from_cell(cell); - if (!eval(macc.bit_ports, undef, cell)) - return false; - for (auto &port : macc.ports) { if (!eval(port.in_a, undef, cell)) return false; diff --git a/kernel/macc.h b/kernel/macc.h index 4af08cfd8..55940769d 100644 --- a/kernel/macc.h +++ b/kernel/macc.h @@ -30,14 +30,11 @@ struct Macc RTLIL::SigSpec in_a, in_b; bool is_signed, do_subtract; }; - std::vector ports; - RTLIL::SigSpec bit_ports; void optimize(int width) { std::vector new_ports; - RTLIL::SigSpec new_bit_ports; RTLIL::Const off(0, width); for (auto &port : ports) @@ -48,11 +45,6 @@ struct Macc if (GetSize(port.in_a) < GetSize(port.in_b)) std::swap(port.in_a, port.in_b); - if (GetSize(port.in_a) == 1 && GetSize(port.in_b) == 0 && !port.is_signed && !port.do_subtract) { - bit_ports.append(port.in_a); - continue; - } - if (port.in_a.is_fully_const() && port.in_b.is_fully_const()) { RTLIL::Const v = port.in_a.as_const(); if (GetSize(port.in_b)) @@ -79,12 +71,6 @@ struct Macc new_ports.push_back(port); } - for (auto &bit : bit_ports) - if (bit == State::S1) - off = const_add(off, RTLIL::Const(1, width), false, false, width); - else if (bit != State::S0) - new_bit_ports.append(bit); - if (off.as_bool()) { port_t port; port.in_a = off; @@ -94,7 +80,6 @@ struct Macc } new_ports.swap(ports); - bit_ports = new_bit_ports; } void from_cell(RTLIL::Cell *cell) @@ -102,7 +87,6 @@ struct Macc RTLIL::SigSpec port_a = cell->getPort(ID::A); ports.clear(); - bit_ports = cell->getPort(ID::B); auto config_bits = cell->getParam(ID::CONFIG); int config_cursor = 0; @@ -145,6 +129,9 @@ struct Macc ports.push_back(this_port); } + for (auto bit : cell->getPort(ID::B)) + ports.push_back(port_t{{bit}, {}, false, false}); + log_assert(config_cursor == config_width); log_assert(port_a_cursor == GetSize(port_a)); } @@ -190,11 +177,11 @@ struct Macc } cell->setPort(ID::A, port_a); - cell->setPort(ID::B, bit_ports); + cell->setPort(ID::B, {}); cell->setParam(ID::CONFIG, config_bits); cell->setParam(ID::CONFIG_WIDTH, GetSize(config_bits)); cell->setParam(ID::A_WIDTH, GetSize(port_a)); - cell->setParam(ID::B_WIDTH, GetSize(bit_ports)); + cell->setParam(ID::B_WIDTH, 0); } bool eval(RTLIL::Const &result) const @@ -219,19 +206,12 @@ struct Macc result = const_add(result, summand, port.is_signed, port.is_signed, GetSize(result)); } - for (auto bit : bit_ports) { - if (bit.wire) - return false; - result = const_add(result, bit.data, false, false, GetSize(result)); - } - return true; } bool is_simple_product() { - return bit_ports.empty() && - ports.size() == 1 && + return ports.size() == 1 && !ports[0].in_b.empty() && !ports[0].do_subtract; } diff --git a/kernel/satgen.cc b/kernel/satgen.cc index ba6d664db..dd15b51f3 100644 --- a/kernel/satgen.cc +++ b/kernel/satgen.cc @@ -743,7 +743,6 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep) if (cell->type == ID($macc)) { std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); Macc macc; @@ -785,12 +784,6 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep) } } - for (int i = 0; i < GetSize(b); i++) { - std::vector val(GetSize(y), ez->CONST_FALSE); - val.at(0) = b.at(i); - tmp = ez->vec_add(tmp, val); - } - if (model_undef) { std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); diff --git a/passes/opt/share.cc b/passes/opt/share.cc index 1408c512a..5d4e2d67d 100644 --- a/passes/opt/share.cc +++ b/passes/opt/share.cc @@ -117,7 +117,7 @@ struct ShareWorker static int bits_macc(const Macc &m, int width) { - int bits = GetSize(m.bit_ports); + int bits = 0; for (auto &p : m.ports) bits += bits_macc_port(p, width); return bits; diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc index 05a3d1702..d89a6fbec 100644 --- a/passes/techmap/alumacc.cc +++ b/passes/techmap/alumacc.cc @@ -283,7 +283,7 @@ struct AlumaccWorker for (auto &it : sig_macc) { auto n = it.second; - RTLIL::SigSpec A, B, C = n->macc.bit_ports; + RTLIL::SigSpec A, B, C; bool a_signed = false, b_signed = false; bool subtract_b = false; alunode_t *alunode; diff --git a/passes/techmap/maccmap.cc b/passes/techmap/maccmap.cc index 2235bdef9..911d66cfa 100644 --- a/passes/techmap/maccmap.cc +++ b/passes/techmap/maccmap.cc @@ -286,19 +286,23 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap) log(" %s %s * %s (%dx%d bits, %s)\n", port.do_subtract ? "sub" : "add", log_signal(port.in_a), log_signal(port.in_b), GetSize(port.in_a), GetSize(port.in_b), port.is_signed ? "signed" : "unsigned"); - if (GetSize(macc.bit_ports) != 0) - log(" add bits %s (%d bits)\n", log_signal(macc.bit_ports), GetSize(macc.bit_ports)); - if (unmap) { typedef std::pair summand_t; std::vector summands; + RTLIL::SigSpec bit_ports; + for (auto &port : macc.ports) { summand_t this_summand; if (GetSize(port.in_b)) { this_summand.first = module->addWire(NEW_ID, width); module->addMul(NEW_ID, port.in_a, port.in_b, this_summand.first, port.is_signed); + } else if (GetSize(port.in_a) == 1 && GetSize(port.in_b) == 0 && !port.is_signed && !port.do_subtract) { + // Mimic old 'bit_ports' treatment in case it's relevant for performance, + // i.e. defer single-bit summands to be the last ones + bit_ports.append(port.in_a); + continue; } else if (GetSize(port.in_a) != width) { this_summand.first = module->addWire(NEW_ID, width); module->addPos(NEW_ID, port.in_a, this_summand.first, port.is_signed); @@ -309,7 +313,7 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap) summands.push_back(this_summand); } - for (auto &bit : macc.bit_ports) + for (auto &bit : bit_ports) summands.push_back(summand_t(bit, false)); if (GetSize(summands) == 0) @@ -346,14 +350,20 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap) else { MaccmapWorker worker(module, width); + RTLIL::SigSpec bit_ports; - for (auto &port : macc.ports) - if (GetSize(port.in_b) == 0) + for (auto &port : macc.ports) { + // Mimic old 'bit_ports' treatment in case it's relevant for performance, + // i.e. defer single-bit summands to be the last ones + if (GetSize(port.in_a) == 1 && GetSize(port.in_b) == 0 && !port.is_signed && !port.do_subtract) + bit_ports.append(port.in_a); + else if (GetSize(port.in_b) == 0) worker.add(port.in_a, port.is_signed, port.do_subtract); else worker.add(port.in_a, port.in_b, port.is_signed, port.do_subtract); + } - for (auto &bit : macc.bit_ports) + for (auto bit : bit_ports) worker.add(bit, 0); module->connect(cell->getPort(ID::Y), worker.synth()); diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc index b9b4d2195..39b7ccd3a 100644 --- a/passes/tests/test_cell.cc +++ b/passes/tests/test_cell.cc @@ -201,18 +201,19 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce this_port.do_subtract = xorshift32(2) == 1; macc.ports.push_back(this_port); } - - wire = module->addWire(ID::B); - wire->width = xorshift32(mulbits_a ? xorshift32(4)+1 : xorshift32(16)+1); - wire->port_input = true; - macc.bit_ports = wire; + // Macc::to_cell sets the input ports + macc.to_cell(cell); wire = module->addWire(ID::Y); wire->width = width; wire->port_output = true; cell->setPort(ID::Y, wire); - macc.to_cell(cell); + // override the B input (macc helpers always sets an empty vector) + wire = module->addWire(ID::B); + wire->width = xorshift32(mulbits_a ? xorshift32(4)+1 : xorshift32(16)+1); + wire->port_input = true; + cell->setPort(ID::B, wire); } if (cell_type == ID($lut)) diff --git a/tests/alumacc/macc_b_port_compat.ys b/tests/alumacc/macc_b_port_compat.ys new file mode 100644 index 000000000..1ed2ad34c --- /dev/null +++ b/tests/alumacc/macc_b_port_compat.ys @@ -0,0 +1,50 @@ +# We don't set the B port on $macc cells anymore, +# test compatibility with older RTLIL files which can +# have the B port populated + +read_verilog < Date: Wed, 8 Jan 2025 13:04:14 +0100 Subject: [PATCH 52/83] write_json: add option to include $scopeinfo cells --- backends/json/json.cc | 27 ++++++++++++++++++----- tests/various/json_scopeinfo.ys | 38 +++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 tests/various/json_scopeinfo.ys diff --git a/backends/json/json.cc b/backends/json/json.cc index 287c01ead..197223c63 100644 --- a/backends/json/json.cc +++ b/backends/json/json.cc @@ -34,6 +34,7 @@ struct JsonWriter bool use_selection; bool aig_mode; bool compat_int_mode; + bool scopeinfo_mode; Design *design; Module *module; @@ -43,9 +44,9 @@ struct JsonWriter dict sigids; pool aig_models; - JsonWriter(std::ostream &f, bool use_selection, bool aig_mode, bool compat_int_mode) : + JsonWriter(std::ostream &f, bool use_selection, bool aig_mode, bool compat_int_mode, bool scopeinfo_mode) : f(f), use_selection(use_selection), aig_mode(aig_mode), - compat_int_mode(compat_int_mode) { } + compat_int_mode(compat_int_mode), scopeinfo_mode(scopeinfo_mode) { } string get_string(string str) { @@ -194,7 +195,7 @@ struct JsonWriter continue; // Eventually we will want to emit $scopeinfo, but currently this // will break JSON netlist consumers like nextpnr - if (c->type == ID($scopeinfo)) + if (!scopeinfo_mode && c->type == ID($scopeinfo)) continue; f << stringf("%s\n", first ? "" : ","); f << stringf(" %s: {\n", get_name(c->name).c_str()); @@ -356,6 +357,9 @@ struct JsonBackend : public Backend { log(" -selected\n"); log(" output only select module\n"); log("\n"); + log(" -scopeinfo\n"); + log(" include $scopeinfo cells in the output\n"); + log("\n"); log("\n"); log("The general syntax of the JSON output created by this command is as follows:\n"); log("\n"); @@ -601,6 +605,7 @@ struct JsonBackend : public Backend { bool aig_mode = false; bool compat_int_mode = false; bool use_selection = false; + bool scopeinfo_mode = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -617,13 +622,17 @@ struct JsonBackend : public Backend { use_selection = true; continue; } + if (args[argidx] == "-scopeinfo") { + scopeinfo_mode = true; + continue; + } break; } extra_args(f, filename, args, argidx); log_header(design, "Executing JSON backend.\n"); - JsonWriter json_writer(*f, use_selection, aig_mode, compat_int_mode); + JsonWriter json_writer(*f, use_selection, aig_mode, compat_int_mode, scopeinfo_mode); json_writer.write_design(design); } } JsonBackend; @@ -648,6 +657,9 @@ struct JsonPass : public Pass { log(" emit 32-bit or smaller fully-defined parameter values directly\n"); log(" as JSON numbers (for compatibility with old parsers)\n"); log("\n"); + log(" -scopeinfo\n"); + log(" include $scopeinfo cells in the output\n"); + log("\n"); log("See 'help write_json' for a description of the JSON format used.\n"); log("\n"); } @@ -656,6 +668,7 @@ struct JsonPass : public Pass { std::string filename; bool aig_mode = false; bool compat_int_mode = false; + bool scopeinfo_mode = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -672,6 +685,10 @@ struct JsonPass : public Pass { compat_int_mode = true; continue; } + if (args[argidx] == "-scopeinfo") { + scopeinfo_mode = true; + continue; + } break; } extra_args(args, argidx, design); @@ -693,7 +710,7 @@ struct JsonPass : public Pass { f = &buf; } - JsonWriter json_writer(*f, true, aig_mode, compat_int_mode); + JsonWriter json_writer(*f, true, aig_mode, compat_int_mode, scopeinfo_mode); json_writer.write_design(design); if (!empty) { diff --git a/tests/various/json_scopeinfo.ys b/tests/various/json_scopeinfo.ys new file mode 100644 index 000000000..50219f16e --- /dev/null +++ b/tests/various/json_scopeinfo.ys @@ -0,0 +1,38 @@ +read_verilog < Date: Wed, 8 Jan 2025 14:46:47 +0100 Subject: [PATCH 53/83] emit $scopeinfo cells by default --- backends/json/json.cc | 22 ++++++++++------------ tests/various/json_scopeinfo.ys | 12 ++++++------ 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/backends/json/json.cc b/backends/json/json.cc index 197223c63..20d42f626 100644 --- a/backends/json/json.cc +++ b/backends/json/json.cc @@ -193,8 +193,6 @@ struct JsonWriter for (auto c : module->cells()) { if (use_selection && !module->selected(c)) continue; - // Eventually we will want to emit $scopeinfo, but currently this - // will break JSON netlist consumers like nextpnr if (!scopeinfo_mode && c->type == ID($scopeinfo)) continue; f << stringf("%s\n", first ? "" : ","); @@ -357,8 +355,8 @@ struct JsonBackend : public Backend { log(" -selected\n"); log(" output only select module\n"); log("\n"); - log(" -scopeinfo\n"); - log(" include $scopeinfo cells in the output\n"); + log(" -noscopeinfo\n"); + log(" don't include $scopeinfo cells in the output\n"); log("\n"); log("\n"); log("The general syntax of the JSON output created by this command is as follows:\n"); @@ -605,7 +603,7 @@ struct JsonBackend : public Backend { bool aig_mode = false; bool compat_int_mode = false; bool use_selection = false; - bool scopeinfo_mode = false; + bool scopeinfo_mode = true; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -622,8 +620,8 @@ struct JsonBackend : public Backend { use_selection = true; continue; } - if (args[argidx] == "-scopeinfo") { - scopeinfo_mode = true; + if (args[argidx] == "-noscopeinfo") { + scopeinfo_mode = false; continue; } break; @@ -657,8 +655,8 @@ struct JsonPass : public Pass { log(" emit 32-bit or smaller fully-defined parameter values directly\n"); log(" as JSON numbers (for compatibility with old parsers)\n"); log("\n"); - log(" -scopeinfo\n"); - log(" include $scopeinfo cells in the output\n"); + log(" -noscopeinfo\n"); + log(" don't include $scopeinfo cells in the output\n"); log("\n"); log("See 'help write_json' for a description of the JSON format used.\n"); log("\n"); @@ -668,7 +666,7 @@ struct JsonPass : public Pass { std::string filename; bool aig_mode = false; bool compat_int_mode = false; - bool scopeinfo_mode = false; + bool scopeinfo_mode = true; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -685,8 +683,8 @@ struct JsonPass : public Pass { compat_int_mode = true; continue; } - if (args[argidx] == "-scopeinfo") { - scopeinfo_mode = true; + if (args[argidx] == "-noscopeinfo") { + scopeinfo_mode = false; continue; } break; diff --git a/tests/various/json_scopeinfo.ys b/tests/various/json_scopeinfo.ys index 50219f16e..a5adbde10 100644 --- a/tests/various/json_scopeinfo.ys +++ b/tests/various/json_scopeinfo.ys @@ -26,13 +26,13 @@ flatten -scopename prep write_json json_scopeinfo.out -!grep -qvF '$scopeinfo' json_scopeinfo.out - -write_json -scopeinfo json_scopeinfo.out !grep -qF '$scopeinfo' json_scopeinfo.out +write_json -noscopeinfo json_scopeinfo.out +!grep -qvF '$scopeinfo' json_scopeinfo.out + json -o json_scopeinfo.out -!grep -qvF '$scopeinfo' json_scopeinfo.out - -json -scopeinfo -o json_scopeinfo.out !grep -qF '$scopeinfo' json_scopeinfo.out + +json -noscopeinfo -o json_scopeinfo.out +!grep -qvF '$scopeinfo' json_scopeinfo.out From 828ccfac4bf2f2d823d30b647da98b72363c72c0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 9 Jan 2025 00:21:05 +0000 Subject: [PATCH 54/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5842a8bc3..195404e1d 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.48+57 +YOSYS_VER := 0.48+62 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 13b183c9c550c296a7071e36f91e8437831d9cd3 Mon Sep 17 00:00:00 2001 From: mikesinouye Date: Thu, 9 Jan 2025 18:30:23 -0800 Subject: [PATCH 55/83] Add option for a custom flatten block separator char --- passes/techmap/flatten.cc | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/passes/techmap/flatten.cc b/passes/techmap/flatten.cc index ea5855a09..619fa4a68 100644 --- a/passes/techmap/flatten.cc +++ b/passes/techmap/flatten.cc @@ -28,22 +28,22 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -IdString concat_name(RTLIL::Cell *cell, IdString object_name) +IdString concat_name(RTLIL::Cell *cell, IdString object_name, const std::string &separator = ".") { if (object_name[0] == '\\') - return stringf("%s.%s", cell->name.c_str(), object_name.c_str() + 1); + return stringf("%s%s%s", cell->name.c_str(), separator.c_str(), object_name.c_str() + 1); else { std::string object_name_str = object_name.str(); if (object_name_str.substr(0, 8) == "$flatten") object_name_str.erase(0, 8); - return stringf("$flatten%s.%s", cell->name.c_str(), object_name_str.c_str()); + return stringf("$flatten%s%s%s", cell->name.c_str(), separator.c_str(), object_name_str.c_str()); } } template -IdString map_name(RTLIL::Cell *cell, T *object) +IdString map_name(RTLIL::Cell *cell, T *object, const std::string &separator = ".") { - return cell->module->uniquify(concat_name(cell, object->name)); + return cell->module->uniquify(concat_name(cell, object->name, separator)); } void map_sigspec(const dict &map, RTLIL::SigSpec &sig, RTLIL::Module *into = nullptr) @@ -60,6 +60,7 @@ struct FlattenWorker bool ignore_wb = false; bool create_scopeinfo = true; bool create_scopename = false; + std::string separator = "."; template void map_attributes(RTLIL::Cell *cell, T *object, IdString orig_object_name) @@ -107,13 +108,13 @@ struct FlattenWorker } } - void flatten_cell(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl, SigMap &sigmap, std::vector &new_cells) + void flatten_cell(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl, SigMap &sigmap, std::vector &new_cells, const std::string &separator) { // Copy the contents of the flattened cell dict memory_map; for (auto &tpl_memory_it : tpl->memories) { - RTLIL::Memory *new_memory = module->addMemory(map_name(cell, tpl_memory_it.second), tpl_memory_it.second); + RTLIL::Memory *new_memory = module->addMemory(map_name(cell, tpl_memory_it.second, separator), tpl_memory_it.second); map_attributes(cell, new_memory, tpl_memory_it.second->name); memory_map[tpl_memory_it.first] = new_memory->name; design->select(module, new_memory); @@ -127,7 +128,7 @@ struct FlattenWorker RTLIL::Wire *new_wire = nullptr; if (tpl_wire->name[0] == '\\') { - RTLIL::Wire *hier_wire = module->wire(concat_name(cell, tpl_wire->name)); + RTLIL::Wire *hier_wire = module->wire(concat_name(cell, tpl_wire->name, separator)); if (hier_wire != nullptr && hier_wire->get_bool_attribute(ID::hierconn)) { hier_wire->attributes.erase(ID::hierconn); if (GetSize(hier_wire) < GetSize(tpl_wire)) { @@ -139,7 +140,7 @@ struct FlattenWorker } } if (new_wire == nullptr) { - new_wire = module->addWire(map_name(cell, tpl_wire), tpl_wire); + new_wire = module->addWire(map_name(cell, tpl_wire, separator), tpl_wire); new_wire->port_input = new_wire->port_output = false; new_wire->port_id = false; } @@ -150,7 +151,7 @@ struct FlattenWorker } for (auto &tpl_proc_it : tpl->processes) { - RTLIL::Process *new_proc = module->addProcess(map_name(cell, tpl_proc_it.second), tpl_proc_it.second); + RTLIL::Process *new_proc = module->addProcess(map_name(cell, tpl_proc_it.second, separator), tpl_proc_it.second); map_attributes(cell, new_proc, tpl_proc_it.second->name); for (auto new_proc_sync : new_proc->syncs) for (auto &memwr_action : new_proc_sync->mem_write_actions) @@ -161,14 +162,14 @@ struct FlattenWorker } for (auto tpl_cell : tpl->cells()) { - RTLIL::Cell *new_cell = module->addCell(map_name(cell, tpl_cell), tpl_cell); + RTLIL::Cell *new_cell = module->addCell(map_name(cell, tpl_cell, separator), tpl_cell); map_attributes(cell, new_cell, tpl_cell->name); if (new_cell->has_memid()) { IdString memid = new_cell->getParam(ID::MEMID).decode_string(); new_cell->setParam(ID::MEMID, Const(memory_map.at(memid).str())); } else if (new_cell->is_mem_cell()) { IdString memid = new_cell->getParam(ID::MEMID).decode_string(); - new_cell->setParam(ID::MEMID, Const(concat_name(cell, memid).str())); + new_cell->setParam(ID::MEMID, Const(concat_name(cell, memid, separator).str())); } auto rewriter = [&](RTLIL::SigSpec &sig) { map_sigspec(wire_map, sig); }; new_cell->rewrite_sigspecs(rewriter); @@ -279,7 +280,7 @@ struct FlattenWorker module->rename(scopeinfo, cell_name); } - void flatten_module(RTLIL::Design *design, RTLIL::Module *module, pool &used_modules) + void flatten_module(RTLIL::Design *design, RTLIL::Module *module, pool &used_modules, const std::string &separator) { if (!design->selected(module) || module->get_blackbox_attribute(ignore_wb)) return; @@ -308,7 +309,7 @@ struct FlattenWorker // If a design is fully selected and has a top module defined, topological sorting ensures that all cells // added during flattening are black boxes, and flattening is finished in one pass. However, when flattening // individual modules, this isn't the case, and the newly added cells might have to be flattened further. - flatten_cell(design, module, cell, tpl, sigmap, worklist); + flatten_cell(design, module, cell, tpl, sigmap, worklist, separator); } } }; @@ -345,6 +346,9 @@ struct FlattenPass : public Pass { log(" with a public name the enclosing scope can be found via their\n"); log(" 'hdlname' attribute.\n"); log("\n"); + log(" -separator \n"); + log(" Use this separator char instead of '.' when concatenating design levels.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { @@ -367,6 +371,10 @@ struct FlattenPass : public Pass { worker.create_scopename = true; continue; } + if (args[argidx] == "-separator" && argidx + 1 < args.size()) { + worker.separator = args[++argidx]; + continue; + } break; } extra_args(args, argidx, design); @@ -401,7 +409,7 @@ struct FlattenPass : public Pass { log_error("Cannot flatten a design containing recursive instantiations.\n"); for (auto module : topo_modules.sorted) - worker.flatten_module(design, module, used_modules); + worker.flatten_module(design, module, used_modules, worker.separator); if (top != nullptr) for (auto module : design->modules().to_vector()) From 27be9a6b77fb59bfd2b8f63961572ec1d25fd67a Mon Sep 17 00:00:00 2001 From: Larry Doolittle Date: Fri, 10 Jan 2025 14:03:09 -0800 Subject: [PATCH 56/83] keep_hierarchy.cc: use strictly correct syntax for printf of uint64_t values Removes two warnings from the compile, at least on amd64 arch --- passes/hierarchy/keep_hierarchy.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/passes/hierarchy/keep_hierarchy.cc b/passes/hierarchy/keep_hierarchy.cc index bfae9fa38..9d77b5239 100644 --- a/passes/hierarchy/keep_hierarchy.cc +++ b/passes/hierarchy/keep_hierarchy.cc @@ -17,6 +17,7 @@ * */ +#include #include "kernel/yosys.h" #include "kernel/cost.h" @@ -66,7 +67,7 @@ struct ThresholdHierarchyKeeping { } if (size > threshold) { - log("Keeping %s (estimated size above threshold: %llu > %llu).\n", log_id(module), size, threshold); + log("Keeping %s (estimated size above threshold: %" PRIu64 " > %" PRIu64 ").\n", log_id(module), size, threshold); module->set_bool_attribute(ID::keep_hierarchy); size = 0; } From 502c39b875f788bae422047fbbc06f2ef5fc17f0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 11 Jan 2025 00:21:05 +0000 Subject: [PATCH 57/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 195404e1d..90b33970a 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.48+62 +YOSYS_VER := 0.48+70 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From a2805b15c9d651852b6d969701943a14c014d9b9 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 14 Jan 2025 12:36:24 +0100 Subject: [PATCH 58/83] hashlib: fix hash_obj_ops discarding hash value --- kernel/hashlib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 188b176b4..ff33c3db3 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -265,7 +265,7 @@ struct hash_obj_ops { template static inline Hasher hash_into(const T *a, Hasher h) { if (a) - a->hash_into(h); + h = a->hash_into(h); else h.eat(0); return h; From a58481e9b776ad81679c25fa2694efefcd422826 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 14 Jan 2025 12:39:15 +0100 Subject: [PATCH 59/83] mark all hash_into methods nodiscard --- frontends/ast/ast.h | 2 +- kernel/bitpattern.h | 2 +- kernel/cellaigs.h | 4 ++-- kernel/drivertools.h | 24 ++++++++++++------------ kernel/functional.h | 4 ++-- kernel/hashlib.h | 24 ++++++++++++------------ kernel/modtools.h | 4 ++-- kernel/rtlil.h | 22 +++++++++++----------- kernel/scopeinfo.h | 4 ++-- kernel/sigtools.h | 4 ++-- kernel/timinginfo.h | 4 ++-- kernel/yosys_common.h | 2 +- kernel/yw.h | 2 +- passes/cmds/dft_tag.cc | 2 +- passes/cmds/example_dt.cc | 2 +- passes/equiv/equiv_struct.cc | 2 +- passes/proc/proc_dlatch.cc | 2 +- passes/sat/recover_names.cc | 4 ++-- passes/techmap/clockgate.cc | 2 +- passes/techmap/flowmap.cc | 2 +- techlibs/quicklogic/ql_dsp_simd.cc | 2 +- 21 files changed, 60 insertions(+), 60 deletions(-) diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index f7f087080..2c2d408ce 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -177,7 +177,7 @@ namespace AST { // for dict<> and pool<> unsigned int hashidx_; - Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } // this nodes type AstNodeType type; diff --git a/kernel/bitpattern.h b/kernel/bitpattern.h index a9dc98a33..821490dca 100644 --- a/kernel/bitpattern.h +++ b/kernel/bitpattern.h @@ -43,7 +43,7 @@ struct BitPatternPool return false; return bitdata == other.bitdata; } - Hasher hash_into(Hasher h) const { + [[nodiscard]] Hasher hash_into(Hasher h) const { if (!cached_hash) cached_hash = run_hash(bitdata); h.eat(cached_hash); diff --git a/kernel/cellaigs.h b/kernel/cellaigs.h index dd1b6dde6..f6afcde5e 100644 --- a/kernel/cellaigs.h +++ b/kernel/cellaigs.h @@ -34,7 +34,7 @@ struct AigNode AigNode(); bool operator==(const AigNode &other) const; - Hasher hash_into(Hasher h) const; + [[nodiscard]] Hasher hash_into(Hasher h) const; }; struct Aig @@ -44,7 +44,7 @@ struct Aig Aig(Cell *cell); bool operator==(const Aig &other) const; - Hasher hash_into(Hasher h) const; + [[nodiscard]] Hasher hash_into(Hasher h) const; }; YOSYS_NAMESPACE_END diff --git a/kernel/drivertools.h b/kernel/drivertools.h index 23eba9f1c..d46217da5 100644 --- a/kernel/drivertools.h +++ b/kernel/drivertools.h @@ -74,7 +74,7 @@ struct DriveBitWire return offset < other.offset; } - Hasher hash_into(Hasher h) const; + [[nodiscard]] Hasher hash_into(Hasher h) const; operator SigBit() const @@ -105,7 +105,7 @@ struct DriveBitPort return offset < other.offset; } - Hasher hash_into(Hasher h) const; + [[nodiscard]] Hasher hash_into(Hasher h) const; }; @@ -129,7 +129,7 @@ struct DriveBitMarker return offset < other.offset; } - Hasher hash_into(Hasher h) const; + [[nodiscard]] Hasher hash_into(Hasher h) const; }; @@ -164,7 +164,7 @@ public: return multiple_ == other.multiple_; } - Hasher hash_into(Hasher h) const; + [[nodiscard]] Hasher hash_into(Hasher h) const; }; struct DriveBit @@ -352,7 +352,7 @@ public: return *this; } - Hasher hash_into(Hasher h) const; + [[nodiscard]] Hasher hash_into(Hasher h) const; bool operator==(const DriveBit &other) const { @@ -473,7 +473,7 @@ struct DriveChunkWire return offset < other.offset; } - Hasher hash_into(Hasher h) const; + [[nodiscard]] Hasher hash_into(Hasher h) const; explicit operator SigChunk() const { @@ -531,7 +531,7 @@ struct DriveChunkPort return offset < other.offset; } - Hasher hash_into(Hasher h) const; + [[nodiscard]] Hasher hash_into(Hasher h) const; }; @@ -572,7 +572,7 @@ struct DriveChunkMarker return offset < other.offset; } - Hasher hash_into(Hasher h) const; + [[nodiscard]] Hasher hash_into(Hasher h) const; }; struct DriveChunkMultiple @@ -612,7 +612,7 @@ public: return false; // TODO implement, canonicalize order } - Hasher hash_into(Hasher h) const; + [[nodiscard]] Hasher hash_into(Hasher h) const; }; struct DriveChunk @@ -863,7 +863,7 @@ public: bool try_append(DriveBit const &bit); bool try_append(DriveChunk const &chunk); - Hasher hash_into(Hasher h) const; + [[nodiscard]] Hasher hash_into(Hasher h) const; bool operator==(const DriveChunk &other) const { @@ -1074,7 +1074,7 @@ public: hash_ |= (hash_ == 0); } - Hasher hash_into(Hasher h) const; + [[nodiscard]] Hasher hash_into(Hasher h) const; bool operator==(DriveSpec const &other) const { updhash(); @@ -1112,7 +1112,7 @@ private: bool operator==(const DriveBitId &other) const { return id == other.id; } bool operator!=(const DriveBitId &other) const { return id != other.id; } bool operator<(const DriveBitId &other) const { return id < other.id; } - Hasher hash_into(Hasher h) const; + [[nodiscard]] Hasher hash_into(Hasher h) const; }; // Essentially a dict> but using less memory // and fewer allocations diff --git a/kernel/functional.h b/kernel/functional.h index e13282140..7e5becef4 100644 --- a/kernel/functional.h +++ b/kernel/functional.h @@ -151,7 +151,7 @@ namespace Functional { // returns the data width of a bitvector sort, errors out for other sorts int data_width() const { return std::get<1>(_v).second; } bool operator==(Sort const& other) const { return _v == other._v; } - Hasher hash_into(Hasher h) const { h.eat(_v); return h; } + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(_v); return h; } }; class IR; class Factory; @@ -225,7 +225,7 @@ namespace Functional { const RTLIL::Const &as_const() const { return std::get(_extra); } std::pair as_idstring_pair() const { return std::get>(_extra); } int as_int() const { return std::get(_extra); } - Hasher hash_into(Hasher h) const { + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat((unsigned int) _fn); h.eat(_extra); return h; diff --git a/kernel/hashlib.h b/kernel/hashlib.h index ff33c3db3..4acfa7f2d 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -162,7 +162,7 @@ struct hash_ops { static inline bool cmp(const T &a, const T &b) { return a == b; } - static inline Hasher hash_into(const T &a, Hasher h) { + [[nodiscard]] static inline Hasher hash_into(const T &a, Hasher h) { if constexpr (std::is_integral_v) { static_assert(sizeof(T) <= sizeof(uint64_t)); if (sizeof(T) == sizeof(uint64_t)) @@ -189,7 +189,7 @@ template struct hash_ops> { static inline bool cmp(std::pair a, std::pair b) { return a == b; } - static inline Hasher hash_into(std::pair a, Hasher h) { + [[nodiscard]] static inline Hasher hash_into(std::pair a, Hasher h) { h = hash_ops

::hash_into(a.first, h); h = hash_ops::hash_into(a.second, h); return h; @@ -217,7 +217,7 @@ template struct hash_ops> { static inline bool cmp(std::vector a, std::vector b) { return a == b; } - static inline Hasher hash_into(std::vector a, Hasher h) { + [[nodiscard]] static inline Hasher hash_into(std::vector a, Hasher h) { h.eat((uint32_t)a.size()); for (auto k : a) h.eat(k); @@ -229,7 +229,7 @@ template struct hash_ops> { static inline bool cmp(std::array a, std::array b) { return a == b; } - static inline Hasher hash_into(std::array a, Hasher h) { + [[nodiscard]] static inline Hasher hash_into(std::array a, Hasher h) { for (const auto& k : a) h = hash_ops::hash_into(k, h); return h; @@ -240,7 +240,7 @@ struct hash_cstr_ops { static inline bool cmp(const char *a, const char *b) { return strcmp(a, b) == 0; } - static inline Hasher hash_into(const char *a, Hasher h) { + [[nodiscard]] static inline Hasher hash_into(const char *a, Hasher h) { while (*a) h.hash32(*(a++)); return h; @@ -253,7 +253,7 @@ struct hash_ptr_ops { static inline bool cmp(const void *a, const void *b) { return a == b; } - static inline Hasher hash_into(const void *a, Hasher h) { + [[nodiscard]] static inline Hasher hash_into(const void *a, Hasher h) { return hash_ops::hash_into((uintptr_t)a, h); } }; @@ -263,7 +263,7 @@ struct hash_obj_ops { return a == b; } template - static inline Hasher hash_into(const T *a, Hasher h) { + [[nodiscard]] static inline Hasher hash_into(const T *a, Hasher h) { if (a) h = a->hash_into(h); else @@ -295,7 +295,7 @@ template<> struct hash_ops { static inline bool cmp(std::monostate a, std::monostate b) { return a == b; } - static inline Hasher hash_into(std::monostate, Hasher h) { + [[nodiscard]] static inline Hasher hash_into(std::monostate, Hasher h) { return h; } }; @@ -304,7 +304,7 @@ template struct hash_ops> { static inline bool cmp(std::variant a, std::variant b) { return a == b; } - static inline Hasher hash_into(std::variant a, Hasher h) { + [[nodiscard]] static inline Hasher hash_into(std::variant a, Hasher h) { std::visit([& h](const auto &v) { h.eat(v); }, a); h.eat(a.index()); return h; @@ -315,7 +315,7 @@ template struct hash_ops> { static inline bool cmp(std::optional a, std::optional b) { return a == b; } - static inline Hasher hash_into(std::optional a, Hasher h) { + [[nodiscard]] static inline Hasher hash_into(std::optional a, Hasher h) { if(a.has_value()) h.eat(*a); else @@ -788,7 +788,7 @@ public: return !operator==(other); } - Hasher hash_into(Hasher h) const { + [[nodiscard]] Hasher hash_into(Hasher h) const { for (auto &it : entries) { Hasher entry_hash; entry_hash.eat(it.udata.first); @@ -1158,7 +1158,7 @@ public: return !operator==(other); } - Hasher hash_into(Hasher h) const { + [[nodiscard]] Hasher hash_into(Hasher h) const { for (auto &it : entries) { h.commutative_eat(ops.hash(it.udata).yield()); } diff --git a/kernel/modtools.h b/kernel/modtools.h index 921df304c..27ba98d7d 100644 --- a/kernel/modtools.h +++ b/kernel/modtools.h @@ -48,7 +48,7 @@ struct ModIndex : public RTLIL::Monitor return cell == other.cell && port == other.port && offset == other.offset; } - Hasher hash_into(Hasher h) const { + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(cell->name); h.eat(port); h.eat(offset); @@ -321,7 +321,7 @@ struct ModWalker return cell == other.cell && port == other.port && offset == other.offset; } - Hasher hash_into(Hasher h) const { + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(cell->name); h.eat(port); h.eat(offset); diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 330af649f..ce66c5af5 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -362,7 +362,7 @@ struct RTLIL::IdString *this = IdString(); } - Hasher hash_into(Hasher h) const { return hash_ops::hash_into(index_, h); } + [[nodiscard]] Hasher hash_into(Hasher h) const { return hash_ops::hash_into(index_, h); } Hasher hash_top() const { Hasher h; @@ -821,7 +821,7 @@ public: bv.resize(width, bv.empty() ? RTLIL::State::Sx : bv.back()); } - inline Hasher hash_into(Hasher h) const { + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(size()); for (auto b : *this) h.eat(b); @@ -914,7 +914,7 @@ struct RTLIL::SigBit bool operator <(const RTLIL::SigBit &other) const; bool operator ==(const RTLIL::SigBit &other) const; bool operator !=(const RTLIL::SigBit &other) const; - Hasher hash_into(Hasher h) const; + [[nodiscard]] Hasher hash_into(Hasher h) const; Hasher hash_top() const; }; @@ -1115,7 +1115,7 @@ public: operator std::vector() const { return bits(); } const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; } - Hasher hash_into(Hasher h) const { if (!hash_) updhash(); h.eat(hash_); return h; } + [[nodiscard]] Hasher hash_into(Hasher h) const { if (!hash_) updhash(); h.eat(hash_); return h; } #ifndef NDEBUG void check(Module *mod = nullptr) const; @@ -1157,7 +1157,7 @@ struct RTLIL::Selection struct RTLIL::Monitor { Hasher::hash_t hashidx_; - Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } Monitor() { static unsigned int hashidx_count = 123456789; @@ -1180,7 +1180,7 @@ struct define_map_t; struct RTLIL::Design { Hasher::hash_t hashidx_; - Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } pool monitors; dict scratchpad; @@ -1285,7 +1285,7 @@ struct RTLIL::Design struct RTLIL::Module : public RTLIL::AttrObject { Hasher::hash_t hashidx_; - Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } protected: void add(RTLIL::Wire *wire); @@ -1640,7 +1640,7 @@ void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire); struct RTLIL::Wire : public RTLIL::AttrObject { Hasher::hash_t hashidx_; - Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } protected: // use module->addWire() and module->remove() to create or destroy wires @@ -1679,7 +1679,7 @@ inline int GetSize(RTLIL::Wire *wire) { struct RTLIL::Memory : public RTLIL::AttrObject { Hasher::hash_t hashidx_; - Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } Memory(); @@ -1694,7 +1694,7 @@ struct RTLIL::Memory : public RTLIL::AttrObject struct RTLIL::Cell : public RTLIL::AttrObject { Hasher::hash_t hashidx_; - Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } protected: // use module->addCell() and module->remove() to create or destroy cells @@ -1804,7 +1804,7 @@ struct RTLIL::SyncRule struct RTLIL::Process : public RTLIL::AttrObject { Hasher::hash_t hashidx_; - Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; } protected: // use module->addProcess() and module->remove() to create or destroy processes diff --git a/kernel/scopeinfo.h b/kernel/scopeinfo.h index f3ae0d7b6..703dc315f 100644 --- a/kernel/scopeinfo.h +++ b/kernel/scopeinfo.h @@ -169,7 +169,7 @@ public: return !(*this == other); } - Hasher hash_into(Hasher h) const + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(scope_name); h.eat(target); @@ -325,7 +325,7 @@ struct ModuleItem { Cell *cell() const { return type == Type::Cell ? static_cast(ptr) : nullptr; } bool operator==(const ModuleItem &other) const { return ptr == other.ptr && type == other.type; } - Hasher hash_into(Hasher h) const { h.eat(ptr); return h; } + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(ptr); return h; } }; static inline void log_dump_val_worker(typename IdTree::Cursor cursor ) { log("%p %s", cursor.target, log_id(cursor.scope_name)); } diff --git a/kernel/sigtools.h b/kernel/sigtools.h index a22685ee2..3b0d7b40d 100644 --- a/kernel/sigtools.h +++ b/kernel/sigtools.h @@ -29,7 +29,7 @@ struct SigPool struct bitDef_t : public std::pair { bitDef_t() : std::pair(NULL, 0) { } bitDef_t(const RTLIL::SigBit &bit) : std::pair(bit.wire, bit.offset) { } - Hasher hash_into(Hasher h) const { + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(first->name); h.eat(second); return h; @@ -147,7 +147,7 @@ struct SigSet struct bitDef_t : public std::pair { bitDef_t() : std::pair(NULL, 0) { } bitDef_t(const RTLIL::SigBit &bit) : std::pair(bit.wire, bit.offset) { } - Hasher hash_into(Hasher h) const { + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(first->name); h.eat(second); return h; diff --git a/kernel/timinginfo.h b/kernel/timinginfo.h index 677bbecb8..ff60415bd 100644 --- a/kernel/timinginfo.h +++ b/kernel/timinginfo.h @@ -44,7 +44,7 @@ struct TimingInfo return {}; return port[offset]; } - Hasher hash_into(Hasher h) const { + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(name); h.eat(offset); return h; @@ -56,7 +56,7 @@ struct TimingInfo BitBit(const NameBit &first, const NameBit &second) : first(first), second(second) {} BitBit(const SigBit &first, const SigBit &second) : first(first), second(second) {} bool operator==(const BitBit& bb) const { return bb.first == first && bb.second == second; } - Hasher hash_into(Hasher h) const { + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(first); h.eat(second); return h; diff --git a/kernel/yosys_common.h b/kernel/yosys_common.h index 25a97a8dd..b1d9ce1e6 100644 --- a/kernel/yosys_common.h +++ b/kernel/yosys_common.h @@ -171,7 +171,7 @@ struct shared_str { const char *c_str() const { return content->c_str(); } const string &str() const { return *content; } bool operator==(const shared_str &other) const { return *content == *other.content; } - Hasher hash_into(Hasher h) const { + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(*content); return h; } diff --git a/kernel/yw.h b/kernel/yw.h index 3c3b4fd40..34c688a09 100644 --- a/kernel/yw.h +++ b/kernel/yw.h @@ -35,7 +35,7 @@ struct IdPath : public std::vector bool has_address() const { int tmp; return get_address(tmp); }; bool get_address(int &addr) const; - Hasher hash_into(Hasher h) const { + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(static_cast&&>(*this)); return h; } diff --git a/passes/cmds/dft_tag.cc b/passes/cmds/dft_tag.cc index cecab4d61..ba7d14323 100644 --- a/passes/cmds/dft_tag.cc +++ b/passes/cmds/dft_tag.cc @@ -47,7 +47,7 @@ struct DftTagWorker { bool operator<(const tag_set &other) const { return index < other.index; } bool operator==(const tag_set &other) const { return index == other.index; } - Hasher hash_into(Hasher h) const { h.eat(index); return h; } + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(index); return h; } bool empty() const { return index == 0; } }; diff --git a/passes/cmds/example_dt.cc b/passes/cmds/example_dt.cc index 5f5246de6..2870e062b 100644 --- a/passes/cmds/example_dt.cc +++ b/passes/cmds/example_dt.cc @@ -52,7 +52,7 @@ struct ExampleDtPass : public Pass return name == other.name && parameters == other.parameters; } - Hasher hash_into(Hasher h) const { + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(name); h.eat(parameters); return h; diff --git a/passes/equiv/equiv_struct.cc b/passes/equiv/equiv_struct.cc index 195cb3424..411f0dd5c 100644 --- a/passes/equiv/equiv_struct.cc +++ b/passes/equiv/equiv_struct.cc @@ -46,7 +46,7 @@ struct EquivStructWorker parameters == other.parameters && port_sizes == other.port_sizes; } - Hasher hash_into(Hasher h) const { + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(type); h.eat(parameters); h.eat(port_sizes); diff --git a/passes/proc/proc_dlatch.cc b/passes/proc/proc_dlatch.cc index 2e41afd09..e038a202c 100644 --- a/passes/proc/proc_dlatch.cc +++ b/passes/proc/proc_dlatch.cc @@ -127,7 +127,7 @@ struct proc_dlatch_db_t return signal == other.signal && match == other.match && children == other.children; } - Hasher hash_into(Hasher h) const { + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(signal); h.eat(match); h.eat(children); diff --git a/passes/sat/recover_names.cc b/passes/sat/recover_names.cc index c18beafa1..cddd8771c 100644 --- a/passes/sat/recover_names.cc +++ b/passes/sat/recover_names.cc @@ -46,7 +46,7 @@ struct IdBit { bool operator==(const IdBit &other) const { return name == other.name && bit == other.bit; }; bool operator!=(const IdBit &other) const { return name != other.name || bit != other.bit; }; - Hasher hash_into(Hasher h) const + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(name); h.eat(bit); @@ -64,7 +64,7 @@ struct InvBit { bool operator==(const InvBit &other) const { return bit == other.bit && inverted == other.inverted; }; bool operator!=(const InvBit &other) const { return bit != other.bit || inverted != other.inverted; }; - Hasher hash_into(Hasher h) const + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(bit); h.eat(inverted); diff --git a/passes/techmap/clockgate.cc b/passes/techmap/clockgate.cc index bdfb94170..52851d922 100644 --- a/passes/techmap/clockgate.cc +++ b/passes/techmap/clockgate.cc @@ -233,7 +233,7 @@ struct ClockgatePass : public Pass { SigBit ce_bit; bool pol_clk; bool pol_ce; - Hasher hash_into(Hasher h) const { + [[nodiscard]] Hasher hash_into(Hasher h) const { auto t = std::make_tuple(clk_bit, ce_bit, pol_clk, pol_ce); h.eat(t); return h; diff --git a/passes/techmap/flowmap.cc b/passes/techmap/flowmap.cc index 00d5369e4..61966195c 100644 --- a/passes/techmap/flowmap.cc +++ b/passes/techmap/flowmap.cc @@ -250,7 +250,7 @@ struct FlowGraph { return !(*this == other); } - Hasher hash_into(Hasher h) const + [[nodiscard]] Hasher hash_into(Hasher h) const { std::pair p = {node, is_bottom}; h.eat(p); diff --git a/techlibs/quicklogic/ql_dsp_simd.cc b/techlibs/quicklogic/ql_dsp_simd.cc index bda7fb3bd..fdd2de406 100644 --- a/techlibs/quicklogic/ql_dsp_simd.cc +++ b/techlibs/quicklogic/ql_dsp_simd.cc @@ -53,7 +53,7 @@ struct QlDspSimdPass : public Pass { DspConfig(const DspConfig &ref) = default; DspConfig(DspConfig &&ref) = default; - Hasher hash_into(Hasher h) const { h.eat(connections); return h; } + [[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(connections); return h; } bool operator==(const DspConfig &ref) const { return connections == ref.connections; } }; From 4dbef95792c13f68000857a347935dc0388f94d6 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 14 Jan 2025 12:48:59 +0100 Subject: [PATCH 60/83] mark all hash_top methods nodiscard --- kernel/rtlil.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index ce66c5af5..3d8187e78 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -364,7 +364,7 @@ struct RTLIL::IdString [[nodiscard]] Hasher hash_into(Hasher h) const { return hash_ops::hash_into(index_, h); } - Hasher hash_top() const { + [[nodiscard]] Hasher hash_top() const { Hasher h; h.force((Hasher::hash_t) index_); return h; @@ -915,7 +915,7 @@ struct RTLIL::SigBit bool operator ==(const RTLIL::SigBit &other) const; bool operator !=(const RTLIL::SigBit &other) const; [[nodiscard]] Hasher hash_into(Hasher h) const; - Hasher hash_top() const; + [[nodiscard]] Hasher hash_top() const; }; namespace hashlib { From 901935fbcec42cbf79594efd9cc2877810395715 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 13 Jan 2025 20:21:05 +0100 Subject: [PATCH 61/83] hashlib: merge hash_ops with hash_top_ops for plugin compat --- kernel/hashlib.h | 58 ++++++++++++++++++++++++++++-------------------- kernel/rtlil.h | 14 ++++++++---- 2 files changed, 44 insertions(+), 28 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 4acfa7f2d..d166076d6 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -61,19 +61,9 @@ namespace legacy { } }; -/** - * Hash a type with an accumulator in a record or array context - */ template struct hash_ops; -/** - * Hash a single instance in isolation. - * Can have explicit specialization, but the default redirects to hash_ops - */ -template -struct hash_top_ops; - inline unsigned int mkhash_xorshift(unsigned int a) { if (sizeof(a) == 4) { a ^= a << 13; @@ -147,15 +137,14 @@ private: using Hasher = HasherDJB32; -template -struct hash_top_ops { - static inline bool cmp(const T &a, const T &b) { - return hash_ops::cmp(a, b); - } - static inline Hasher hash(const T &a) { - return hash_ops::hash_into(a, Hasher()); - } -}; +// Boilerplate compressor for trivially implementing +// top-level hash method with hash_into +#define HASH_TOP_LOOP_FST [[nodiscard]] static inline Hasher hash +#define HASH_TOP_LOOP_SND { \ + Hasher h; \ + h.eat(a); \ + return h; \ +} template struct hash_ops { @@ -183,6 +172,7 @@ struct hash_ops { return a.hash_into(h); } } + HASH_TOP_LOOP_FST (const T &a) HASH_TOP_LOOP_SND }; template struct hash_ops> { @@ -194,6 +184,7 @@ template struct hash_ops> { h = hash_ops::hash_into(a.second, h); return h; } + HASH_TOP_LOOP_FST (std::pair a) HASH_TOP_LOOP_SND }; template struct hash_ops> { @@ -211,6 +202,7 @@ template struct hash_ops> { h = element_ops_t::hash_into(std::get(a), h); return h; } + HASH_TOP_LOOP_FST (std::tuple a) HASH_TOP_LOOP_SND }; template struct hash_ops> { @@ -223,6 +215,7 @@ template struct hash_ops> { h.eat(k); return h; } + HASH_TOP_LOOP_FST (std::vector a) HASH_TOP_LOOP_SND }; template struct hash_ops> { @@ -234,6 +227,7 @@ template struct hash_ops> { h = hash_ops::hash_into(k, h); return h; } + HASH_TOP_LOOP_FST (std::array a) HASH_TOP_LOOP_SND }; struct hash_cstr_ops { @@ -245,6 +239,11 @@ struct hash_cstr_ops { h.hash32(*(a++)); return h; } + [[nodiscard]] static inline Hasher hash(const char *a) { + Hasher h; + h = hash_cstr_ops::hash_into(a, h); + return h; + } }; template <> struct hash_ops : hash_cstr_ops {}; @@ -256,6 +255,11 @@ struct hash_ptr_ops { [[nodiscard]] static inline Hasher hash_into(const void *a, Hasher h) { return hash_ops::hash_into((uintptr_t)a, h); } + [[nodiscard]] static inline Hasher hash(const void *a) { + Hasher h; + h = hash_ptr_ops::hash_into(a, h); + return h; + } }; struct hash_obj_ops { @@ -270,6 +274,12 @@ struct hash_obj_ops { h.eat(0); return h; } + template + [[nodiscard]] static inline Hasher hash(const T *a) { + Hasher h; + h = hash_obj_ops::hash_into(a, h); + return h; + } }; /** * If you find yourself using this function, think hard @@ -280,7 +290,7 @@ struct hash_obj_ops { template [[nodiscard]] Hasher::hash_t run_hash(const T& obj) { - return hash_top_ops::hash(obj).yield(); + return hash_ops::hash(obj).yield(); } /** Refer to docs/source/yosys_internals/hashing.rst */ @@ -352,10 +362,10 @@ inline unsigned int hashtable_size(unsigned int min_size) throw std::length_error("hash table exceeded maximum size."); } -template> class dict; -template> class idict; -template> class pool; -template> class mfp; +template> class dict; +template> class idict; +template> class pool; +template> class mfp; template class dict { diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 3d8187e78..f9cacd151 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -398,13 +398,16 @@ struct RTLIL::IdString namespace hashlib { template <> - struct hash_top_ops { + struct hash_ops { static inline bool cmp(const RTLIL::IdString &a, const RTLIL::IdString &b) { return a == b; } - static inline Hasher hash(const RTLIL::IdString id) { + [[nodiscard]] static inline Hasher hash(const RTLIL::IdString id) { return id.hash_top(); } + [[nodiscard]] static inline Hasher hash_into(const RTLIL::IdString id, Hasher h) { + return id.hash_into(h); + } }; }; @@ -920,13 +923,16 @@ struct RTLIL::SigBit namespace hashlib { template <> - struct hash_top_ops { + struct hash_ops { static inline bool cmp(const RTLIL::SigBit &a, const RTLIL::SigBit &b) { return a == b; } - static inline Hasher hash(const RTLIL::SigBit sb) { + [[nodiscard]] static inline Hasher hash(const RTLIL::SigBit sb) { return sb.hash_top(); } + [[nodiscard]] static inline Hasher hash_into(const RTLIL::SigBit sb, Hasher h) { + return sb.hash_into(h); + } }; }; From eac2294cabf31a350716d33e540826f88a60c6f1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 15 Jan 2025 00:20:50 +0000 Subject: [PATCH 62/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 90b33970a..35561acd8 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.48+70 +YOSYS_VER := 0.48+77 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 17d45796a688b5a48caee40c76c7b8af69a8e031 Mon Sep 17 00:00:00 2001 From: "N. Engelhardt" Date: Wed, 15 Jan 2025 15:25:35 +0100 Subject: [PATCH 63/83] ModuleHdlnameIndex: handle objects with private name and hdlname attribute --- kernel/scopeinfo.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/kernel/scopeinfo.h b/kernel/scopeinfo.h index 703dc315f..45d867b62 100644 --- a/kernel/scopeinfo.h +++ b/kernel/scopeinfo.h @@ -337,12 +337,12 @@ template std::vector parse_hdlname(const O* object) { std::vector path; - if (!object->name.isPublic()) - return path; for (auto const &item : object->get_hdlname_attribute()) path.push_back("\\" + item); - if (path.empty()) + if (path.empty() && object->name.isPublic()) path.push_back(object->name); + if (!path.empty() && !(object->name.isPublic() || object->name.begins_with("$paramod") || object->name.begins_with("$abstract"))) + path.pop_back(); return path; } @@ -351,17 +351,22 @@ std::pair, IdString> parse_scopename(const O* object) { std::vector path; IdString trailing = object->name; - if (object->name.isPublic()) { + if (object->name.isPublic() || object->name.begins_with("$paramod") || object->name.begins_with("$abstract")) { for (auto const &item : object->get_hdlname_attribute()) path.push_back("\\" + item); if (!path.empty()) { trailing = path.back(); path.pop_back(); } + } else if (object->has_attribute(ID::hdlname)) { + for (auto const &item : object->get_hdlname_attribute()) + path.push_back("\\" + item); + if (!path.empty()) { + path.pop_back(); + } } else { for (auto const &item : split_tokens(object->get_string_attribute(ID(scopename)), " ")) path.push_back("\\" + item); - } return {path, trailing}; } From d640157ec4b4574f5bda6a10d2f6ddec6ee09585 Mon Sep 17 00:00:00 2001 From: "N. Engelhardt" Date: Wed, 15 Jan 2025 15:56:42 +0100 Subject: [PATCH 64/83] fix some cases of hdlname being added to objects with private names --- frontends/verific/verific.cc | 3 ++- passes/fsm/fsm_extract.cc | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 8f1b07b10..cdd0ed802 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1464,7 +1464,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma log("Importing module %s.\n", RTLIL::id2cstr(module->name)); } import_attributes(module->attributes, nl, nl); - module->set_string_attribute(ID::hdlname, nl->CellBaseName()); + if (module->name.isPublic()) + module->set_string_attribute(ID::hdlname, nl->CellBaseName()); module->set_string_attribute(ID(library), nl->Owner()->Owner()->Name()); #ifdef VERIFIC_VHDL_SUPPORT if (nl->IsFromVhdl()) { diff --git a/passes/fsm/fsm_extract.cc b/passes/fsm/fsm_extract.cc index 6114dd34b..17675b402 100644 --- a/passes/fsm/fsm_extract.cc +++ b/passes/fsm/fsm_extract.cc @@ -377,6 +377,10 @@ static void extract_fsm(RTLIL::Wire *wire) fsm_cell->setPort(ID::CTRL_OUT, ctrl_out); fsm_cell->parameters[ID::NAME] = RTLIL::Const(wire->name.str()); fsm_cell->attributes = wire->attributes; + if(fsm_cell->attributes.count(ID::hdlname)) { + fsm_cell->attributes[ID(scopename)] = fsm_cell->attributes[ID::hdlname]; + fsm_cell->attributes.erase(ID::hdlname); + } fsm_data.copy_to_cell(fsm_cell); // rename original state wire @@ -385,6 +389,10 @@ static void extract_fsm(RTLIL::Wire *wire) wire->attributes.erase(ID::fsm_encoding); wire->name = stringf("$fsm$oldstate%s", wire->name.c_str()); module->wires_[wire->name] = wire; + if(wire->attributes.count(ID::hdlname)) { + wire->attributes[ID(scopename)] = wire->attributes[ID::hdlname]; + wire->attributes.erase(ID::hdlname); + } // unconnect control outputs from old drivers From a5ba1d2ebafd6a3c5e65d238811f59db55414b10 Mon Sep 17 00:00:00 2001 From: "N. Engelhardt" Date: Thu, 16 Jan 2025 12:57:08 +0100 Subject: [PATCH 65/83] fix bugs in handling last id in hdlname to scopename conversion --- kernel/scopeinfo.h | 4 +++- passes/fsm/fsm_extract.cc | 10 ++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/kernel/scopeinfo.h b/kernel/scopeinfo.h index 45d867b62..3bc1a8162 100644 --- a/kernel/scopeinfo.h +++ b/kernel/scopeinfo.h @@ -341,8 +341,10 @@ std::vector parse_hdlname(const O* object) path.push_back("\\" + item); if (path.empty() && object->name.isPublic()) path.push_back(object->name); - if (!path.empty() && !(object->name.isPublic() || object->name.begins_with("$paramod") || object->name.begins_with("$abstract"))) + if (!path.empty() && !(object->name.isPublic() || object->name.begins_with("$paramod") || object->name.begins_with("$abstract"))) { path.pop_back(); + path.push_back(object->name); + } return path; } diff --git a/passes/fsm/fsm_extract.cc b/passes/fsm/fsm_extract.cc index 17675b402..143ae7b54 100644 --- a/passes/fsm/fsm_extract.cc +++ b/passes/fsm/fsm_extract.cc @@ -378,7 +378,10 @@ static void extract_fsm(RTLIL::Wire *wire) fsm_cell->parameters[ID::NAME] = RTLIL::Const(wire->name.str()); fsm_cell->attributes = wire->attributes; if(fsm_cell->attributes.count(ID::hdlname)) { - fsm_cell->attributes[ID(scopename)] = fsm_cell->attributes[ID::hdlname]; + auto hdlname = fsm_cell->get_hdlname_attribute(); + hdlname.pop_back(); + fsm_cell->set_hdlname_attribute(hdlname); + fsm_cell->set_string_attribute(ID(scopename), fsm_cell->get_string_attribute(ID::hdlname)); fsm_cell->attributes.erase(ID::hdlname); } fsm_data.copy_to_cell(fsm_cell); @@ -390,7 +393,10 @@ static void extract_fsm(RTLIL::Wire *wire) wire->name = stringf("$fsm$oldstate%s", wire->name.c_str()); module->wires_[wire->name] = wire; if(wire->attributes.count(ID::hdlname)) { - wire->attributes[ID(scopename)] = wire->attributes[ID::hdlname]; + auto hdlname = wire->get_hdlname_attribute(); + hdlname.pop_back(); + wire->set_hdlname_attribute(hdlname); + wire->set_string_attribute(ID(scopename), wire->get_string_attribute(ID::hdlname)); wire->attributes.erase(ID::hdlname); } From fe79a77e398fab8dc962e49556eec5803aa3be74 Mon Sep 17 00:00:00 2001 From: Gabriel Somlo Date: Thu, 16 Jan 2025 09:23:16 -0500 Subject: [PATCH 66/83] Fix undefined type error in libs/json11/json11.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Under certain conditions, compilation errors out with the following message: "error: ‘uint8_t’ does not name a type" Explicitly including prevents that situation. Signed-off-by: Gabriel Somlo --- libs/json11/json11.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/json11/json11.cpp b/libs/json11/json11.cpp index 189e63881..cdd81c6a9 100644 --- a/libs/json11/json11.cpp +++ b/libs/json11/json11.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include namespace json11 { From 76d85fefac21aebde264b8bd1fe4a675ce61ee4a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 18 Jan 2025 00:19:38 +0000 Subject: [PATCH 67/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 35561acd8..9a94b3f9d 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.48+77 +YOSYS_VER := 0.48+80 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 63074ccb895c504d7a766b199ed7fad42a54e114 Mon Sep 17 00:00:00 2001 From: Peter Gadfort Date: Sat, 18 Jan 2025 10:27:10 -0700 Subject: [PATCH 68/83] add support for passing flatten -separator to flatten in synth --- techlibs/common/synth.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc index 74a484d59..a1ce1ae1b 100644 --- a/techlibs/common/synth.cc +++ b/techlibs/common/synth.cc @@ -98,7 +98,7 @@ struct SynthPass : public ScriptPass { log("\n"); } - string top_module, fsm_opts, memory_opts, abc; + string top_module, fsm_opts, memory_opts, abc, flatten_separator; bool autotop, flatten, noalumacc, nofsm, noabc, noshare, flowmap, booth; int lut; std::vector techmap_maps; @@ -120,6 +120,7 @@ struct SynthPass : public ScriptPass { booth = false; abc = "abc"; techmap_maps.clear(); + flatten_separator = ""; } void execute(std::vector args, RTLIL::Design *design) override @@ -154,6 +155,8 @@ struct SynthPass : public ScriptPass { } if (args[argidx] == "-flatten") { flatten = true; + if (design->scratchpad.count("flatten.separator")) + flatten_separator = design->scratchpad_get_string("flatten.separator"); continue; } if (args[argidx] == "-lut" && argidx + 1 < args.size()) { @@ -239,8 +242,12 @@ struct SynthPass : public ScriptPass { if (check_label("coarse")) { run("proc"); - if (flatten || help_mode) - run("flatten", " (if -flatten)"); + if (flatten || help_mode) { + if (!flatten_separator.empty()) + run(stringf("flatten -separator %s", flatten_separator.c_str()), " (if -flatten)"); + else + run("flatten", " (if -flatten)"); + } run("opt_expr"); run("opt_clean"); run("check"); From c4f90693aa1efe1e416dc385c0ee5e68840a5c31 Mon Sep 17 00:00:00 2001 From: Peter Gadfort Date: Sat, 18 Jan 2025 10:37:56 -0700 Subject: [PATCH 69/83] Revert "add support for passing flatten -separator to flatten in synth" This reverts commit 63074ccb895c504d7a766b199ed7fad42a54e114. --- techlibs/common/synth.cc | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc index a1ce1ae1b..74a484d59 100644 --- a/techlibs/common/synth.cc +++ b/techlibs/common/synth.cc @@ -98,7 +98,7 @@ struct SynthPass : public ScriptPass { log("\n"); } - string top_module, fsm_opts, memory_opts, abc, flatten_separator; + string top_module, fsm_opts, memory_opts, abc; bool autotop, flatten, noalumacc, nofsm, noabc, noshare, flowmap, booth; int lut; std::vector techmap_maps; @@ -120,7 +120,6 @@ struct SynthPass : public ScriptPass { booth = false; abc = "abc"; techmap_maps.clear(); - flatten_separator = ""; } void execute(std::vector args, RTLIL::Design *design) override @@ -155,8 +154,6 @@ struct SynthPass : public ScriptPass { } if (args[argidx] == "-flatten") { flatten = true; - if (design->scratchpad.count("flatten.separator")) - flatten_separator = design->scratchpad_get_string("flatten.separator"); continue; } if (args[argidx] == "-lut" && argidx + 1 < args.size()) { @@ -242,12 +239,8 @@ struct SynthPass : public ScriptPass { if (check_label("coarse")) { run("proc"); - if (flatten || help_mode) { - if (!flatten_separator.empty()) - run(stringf("flatten -separator %s", flatten_separator.c_str()), " (if -flatten)"); - else - run("flatten", " (if -flatten)"); - } + if (flatten || help_mode) + run("flatten", " (if -flatten)"); run("opt_expr"); run("opt_clean"); run("check"); From f0860459ac668a420915bca1628da5e634797f3a Mon Sep 17 00:00:00 2001 From: Peter Gadfort Date: Sat, 18 Jan 2025 10:45:19 -0700 Subject: [PATCH 70/83] add support for using scratchpad value for flatten.separator in flatten command --- passes/techmap/flatten.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/passes/techmap/flatten.cc b/passes/techmap/flatten.cc index 619fa4a68..3425509b1 100644 --- a/passes/techmap/flatten.cc +++ b/passes/techmap/flatten.cc @@ -357,6 +357,9 @@ struct FlattenPass : public Pass { FlattenWorker worker; + if (design->scratchpad.count("flatten.separator")) + worker.separator = design->scratchpad_get_string("flatten.separator"); + size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-wb") { From 37acfce8c4da431a101b90f4aaa77476e33a6a06 Mon Sep 17 00:00:00 2001 From: KrystalDelusion <93062060+KrystalDelusion@users.noreply.github.com> Date: Mon, 20 Jan 2025 11:07:40 +1300 Subject: [PATCH 71/83] test-compile: Update oldest clang for 24.04 Oldest clang on 24.04 appears to be 16. --- .github/workflows/test-compile.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-compile.yml b/.github/workflows/test-compile.yml index 74c3e2639..d798668b1 100644 --- a/.github/workflows/test-compile.yml +++ b/.github/workflows/test-compile.yml @@ -30,7 +30,7 @@ jobs: - ubuntu-latest compiler: # oldest supported - - 'clang-14' + - 'clang-16' - 'gcc-10' # newest, make sure to update maximum standard step to match - 'clang-18' From 2403c406fb331e9d42bd0bb5ee124276762ec58a Mon Sep 17 00:00:00 2001 From: KrystalDelusion <93062060+KrystalDelusion@users.noreply.github.com> Date: Mon, 20 Jan 2025 11:21:17 +1300 Subject: [PATCH 72/83] test-compile: Update latest clang Use clang-19 as latest --- .github/workflows/test-compile.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-compile.yml b/.github/workflows/test-compile.yml index d798668b1..2321866b7 100644 --- a/.github/workflows/test-compile.yml +++ b/.github/workflows/test-compile.yml @@ -33,7 +33,7 @@ jobs: - 'clang-16' - 'gcc-10' # newest, make sure to update maximum standard step to match - - 'clang-18' + - 'clang-19' - 'gcc-13' include: # macOS @@ -72,7 +72,7 @@ jobs: # maximum standard, only on newest compilers - name: Build C++20 - if: ${{ matrix.compiler == 'clang-18' || matrix.compiler == 'gcc-13' }} + if: ${{ matrix.compiler == 'clang-19' || matrix.compiler == 'gcc-13' }} shell: bash run: | make config-$CC_SHORT From 90b1ccf67bd57a3226d59f3d68d2597cd690c03d Mon Sep 17 00:00:00 2001 From: KrystalDelusion <93062060+KrystalDelusion@users.noreply.github.com> Date: Mon, 20 Jan 2025 11:57:47 +1300 Subject: [PATCH 73/83] test-compile: Set oldest clang to 10 clang-11 through clang-16 fail under 24.04, but clang-10 works, so we can move that up to the oldest supported and drop the extra target for ubuntu-20.04 --- .github/workflows/test-compile.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/test-compile.yml b/.github/workflows/test-compile.yml index 2321866b7..203c20bb4 100644 --- a/.github/workflows/test-compile.yml +++ b/.github/workflows/test-compile.yml @@ -30,7 +30,7 @@ jobs: - ubuntu-latest compiler: # oldest supported - - 'clang-16' + - 'clang-10' - 'gcc-10' # newest, make sure to update maximum standard step to match - 'clang-19' @@ -39,9 +39,6 @@ jobs: # macOS - os: macos-13 compiler: 'clang' - # oldest clang not available on ubuntu-latest - - os: ubuntu-20.04 - compiler: 'clang-10' fail-fast: false steps: - name: Checkout Yosys From ab4bda8ae25714dfd6249e136a9021d4afedc278 Mon Sep 17 00:00:00 2001 From: KrystalDelusion <93062060+KrystalDelusion@users.noreply.github.com> Date: Mon, 20 Jan 2025 16:19:36 +1300 Subject: [PATCH 74/83] Docs: Fix links for view/edit source --- docs/source/conf.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/source/conf.py b/docs/source/conf.py index 8c8555b71..0e2f79a56 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -11,6 +11,29 @@ yosys_ver = "0.48" # select HTML theme html_theme = 'furo-ys' html_css_files = ['custom.css'] +html_theme_options: dict[str] = { + "source_repository": "https://github.com/YosysHQ/yosys/", + "source_branch": "main", + "source_directory": "docs/", +} + +# try to fix the readthedocs detection +html_context: dict[str] = { + "READTHEDOCS": True, + "display_github": True, + "github_user": "YosysHQ", + "github_repo": "yosys", + "slug": "yosys", +} + +# override source_branch if not main +git_slug = os.getenv("READTHEDOCS_VERSION_NAME") +if git_slug not in [None, "latest", "stable"]: + html_theme_options["source_branch"] = git_slug + +# edit only works on branches, not tags +if os.getenv("READTHEDOCS_VERSION_TYPE", "branch") != "branch": + html_theme_options["top_of_page_buttons"] = ["view"] # These folders are copied to the documentation's HTML output html_static_path = ['_static', "_images"] From 0c61f1a9a8a6148a7b7642d3784948411a0afb09 Mon Sep 17 00:00:00 2001 From: KrystalDelusion <93062060+KrystalDelusion@users.noreply.github.com> Date: Mon, 20 Jan 2025 16:30:30 +1300 Subject: [PATCH 75/83] conf.py: Fix source_directory --- docs/source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 0e2f79a56..de0b9cf4d 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -14,7 +14,7 @@ html_css_files = ['custom.css'] html_theme_options: dict[str] = { "source_repository": "https://github.com/YosysHQ/yosys/", "source_branch": "main", - "source_directory": "docs/", + "source_directory": "docs/source/", } # try to fix the readthedocs detection From 6b449970ef43cdae945639483e6c23177b45e8d7 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 20 Jan 2025 16:08:42 +0100 Subject: [PATCH 76/83] test-build: Fix missing bzlib.h --- .github/actions/setup-build-env/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/setup-build-env/action.yml b/.github/actions/setup-build-env/action.yml index a2ffb8d3e..dfdcd88c0 100644 --- a/.github/actions/setup-build-env/action.yml +++ b/.github/actions/setup-build-env/action.yml @@ -8,7 +8,7 @@ runs: shell: bash run: | sudo apt-get update - sudo apt-get install gperf build-essential bison flex libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev + sudo apt-get install gperf build-essential bison flex libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev libbz2-dev - name: Install macOS Dependencies if: runner.os == 'macOS' From aa01ef3312a709a90a797beca6eb4002abf7b8df Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 20 Jan 2025 16:15:48 +0100 Subject: [PATCH 77/83] hashlib: simplify loopback. NFC --- kernel/hashlib.h | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index d166076d6..6e3eb32a4 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -142,7 +142,7 @@ using Hasher = HasherDJB32; #define HASH_TOP_LOOP_FST [[nodiscard]] static inline Hasher hash #define HASH_TOP_LOOP_SND { \ Hasher h; \ - h.eat(a); \ + h = hash_into(a, h); \ return h; \ } @@ -239,11 +239,7 @@ struct hash_cstr_ops { h.hash32(*(a++)); return h; } - [[nodiscard]] static inline Hasher hash(const char *a) { - Hasher h; - h = hash_cstr_ops::hash_into(a, h); - return h; - } + HASH_TOP_LOOP_FST (const char *a) HASH_TOP_LOOP_SND }; template <> struct hash_ops : hash_cstr_ops {}; @@ -255,11 +251,7 @@ struct hash_ptr_ops { [[nodiscard]] static inline Hasher hash_into(const void *a, Hasher h) { return hash_ops::hash_into((uintptr_t)a, h); } - [[nodiscard]] static inline Hasher hash(const void *a) { - Hasher h; - h = hash_ptr_ops::hash_into(a, h); - return h; - } + HASH_TOP_LOOP_FST (const void *a) HASH_TOP_LOOP_SND }; struct hash_obj_ops { @@ -275,11 +267,7 @@ struct hash_obj_ops { return h; } template - [[nodiscard]] static inline Hasher hash(const T *a) { - Hasher h; - h = hash_obj_ops::hash_into(a, h); - return h; - } + HASH_TOP_LOOP_FST (const T *a) HASH_TOP_LOOP_SND }; /** * If you find yourself using this function, think hard From a2c26a00f2b55307bea27322c68dc7321c7ebc82 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 20 Jan 2025 16:25:52 +0100 Subject: [PATCH 78/83] hashlib: document merged hash_top_ops with hash_ops --- docs/source/yosys_internals/hashing.rst | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/docs/source/yosys_internals/hashing.rst b/docs/source/yosys_internals/hashing.rst index 338ee5fd6..c6e22c0cf 100644 --- a/docs/source/yosys_internals/hashing.rst +++ b/docs/source/yosys_internals/hashing.rst @@ -97,8 +97,8 @@ Making a type hashable Let's first take a look at the external interface on a simplified level. Generally, to get the hash for ``T obj``, you would call the utility function -``run_hash(const T& obj)``, corresponding to ``hash_top_ops::hash(obj)``, -the default implementation of which is ``hash_ops::hash_into(Hasher(), obj)``. +``run_hash(const T& obj)``, corresponding to ``hash_ops::hash(obj)``, +the default implementation of which uses ``hash_ops::hash_into(Hasher(), obj)``. ``Hasher`` is the class actually implementing the hash function, hiding its initialized internal state, and passing it out on ``hash_t yield()`` with perhaps some finalization steps. @@ -121,8 +121,14 @@ size containers like ``std::vector`` the size of the container is hashed first. That is also how implementing hashing for a custom record data type should be - unless there is strong reason to do otherwise, call ``h.eat(m)`` on the ``Hasher h`` you have received for each member in sequence and ``return -h;``. If you do have a strong reason to do so, look at how -``hash_top_ops`` is implemented in ``kernel/rtlil.h``. +h;``. + +The ``hash_ops::hash(obj)`` method is not indended to be called when +context of implementing the hashing for a record or other compound type. +When writing it, you should connect it to ``hash_ops::hash_into(Hasher h)`` +as shown below. If you have a strong reason to do so, and you have +to create a special implementation for top-level hashing, look at how +``hash_ops::hash(...)`` is implemented in ``kernel/rtlil.h``. Porting plugins from the legacy interface ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -148,6 +154,11 @@ based on the existance and value of `YS_HASHING_VERSION`. h.eat(b); return h; } + Hasher T::hash() const { + Hasher h; + h.eat(*this); + return h; + } #else #error "Unsupported hashing interface" #endif From 3f4f6c17d6fb2a9548c935a8e4c73af5fa326015 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 21 Jan 2025 00:20:11 +0000 Subject: [PATCH 79/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9a94b3f9d..ec47685f2 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.48+80 +YOSYS_VER := 0.48+98 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From d50849ea8395b88c8211bed6aa45b7581fd960aa Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 21 Jan 2025 08:48:29 +0100 Subject: [PATCH 80/83] Copyright year update --- COPYING | 2 +- kernel/register.cc | 2 +- kernel/yosys.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/COPYING b/COPYING index e8b123be2..2d962dddc 100644 --- a/COPYING +++ b/COPYING @@ -1,6 +1,6 @@ ISC License -Copyright (C) 2012 - 2020 Claire Xenia Wolf +Copyright (C) 2012 - 2025 Claire Xenia Wolf Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above diff --git a/kernel/register.cc b/kernel/register.cc index d6e765ce4..11cf5b0e4 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -1221,7 +1221,7 @@ struct LicensePass : public Pass { log(" | |\n"); log(" | yosys -- Yosys Open SYnthesis Suite |\n"); log(" | |\n"); - log(" | Copyright (C) 2012 - 2024 Claire Xenia Wolf |\n"); + log(" | Copyright (C) 2012 - 2025 Claire Xenia Wolf |\n"); log(" | |\n"); log(" | Permission to use, copy, modify, and/or distribute this software for any |\n"); log(" | purpose with or without fee is hereby granted, provided that the above |\n"); diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 7cf60f068..de25d20e2 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -141,7 +141,7 @@ void yosys_banner() log("\n"); log(" /----------------------------------------------------------------------------\\\n"); log(" | yosys -- Yosys Open SYnthesis Suite |\n"); - log(" | Copyright (C) 2012 - 2024 Claire Xenia Wolf |\n"); + log(" | Copyright (C) 2012 - 2025 Claire Xenia Wolf |\n"); log(" | Distributed under an ISC-like license, type \"license\" to see terms |\n"); log(" \\----------------------------------------------------------------------------/\n"); log(" %s\n", yosys_version_str); From 427b5a251bfb511528a177bfa92567b4b3ada3dd Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 21 Jan 2025 14:59:09 +0100 Subject: [PATCH 81/83] Release version 0.49 --- CHANGELOG | 11 ++++++++++- Makefile | 4 ++-- docs/source/conf.py | 4 ++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1ebaeb24a..ec84318aa 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,8 +2,17 @@ List of major changes and improvements between releases ======================================================= -Yosys 0.48 .. Yosys 0.49-dev +Yosys 0.48 .. Yosys 0.49 -------------------------- + * Various + - "$scopeinfo" cells are now part of JSON export by default. + - Added option to specify hierarchical separator for "flatten". + - Improved "wreduce" to handle more cases of operator size reduction. + - Updated hashing interface, see docs/source/yosys_internals/hashing.rst + for breaking API changes. + + * New commands and options + - Added "-noscopeinfo" option to "json" and "write_json" pass. Yosys 0.47 .. Yosys 0.48 -------------------------- diff --git a/Makefile b/Makefile index ec47685f2..a6b742526 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.48+98 +YOSYS_VER := 0.49 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo @@ -169,7 +169,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: - sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline aaa5347.. | wc -l`/;" Makefile +# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline aaa5347.. | wc -l`/;" Makefile ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) diff --git a/docs/source/conf.py b/docs/source/conf.py index de0b9cf4d..a27b4dc64 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -5,8 +5,8 @@ import os project = 'YosysHQ Yosys' author = 'YosysHQ GmbH' -copyright ='2024 YosysHQ GmbH' -yosys_ver = "0.48" +copyright ='2025 YosysHQ GmbH' +yosys_ver = "0.49" # select HTML theme html_theme = 'furo-ys' From e456f2e9724394fc34c899d59a1cb0ee578e96b3 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 21 Jan 2025 15:26:22 +0100 Subject: [PATCH 82/83] Next dev cycle --- CHANGELOG | 3 +++ Makefile | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ec84318aa..d1c1f560a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,9 @@ List of major changes and improvements between releases ======================================================= +Yosys 0.49 .. Yosys 0.50-dev +-------------------------- + Yosys 0.48 .. Yosys 0.49 -------------------------- * Various diff --git a/Makefile b/Makefile index a6b742526..6c63f22cc 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.49 +YOSYS_VER := 0.49+0 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo @@ -169,7 +169,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: -# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline aaa5347.. | wc -l`/;" Makefile + sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 427b5a2.. | wc -l`/;" Makefile ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) From 4a27d93b06848466a1b87864d0e8da619bdab6d9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 00:20:51 +0000 Subject: [PATCH 83/83] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6c63f22cc..896d44203 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.49+0 +YOSYS_VER := 0.49+1 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo