diff --git a/.github/workflows/contributor.yml b/.github/workflows/contributor.yml index 627d00ab3..bbc00ce97 100644 --- a/.github/workflows/contributor.yml +++ b/.github/workflows/contributor.yml @@ -11,7 +11,7 @@ on: jobs: Test: name: "'docs/CONTRIBUTORS' was signed" - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 - run: test_regress/t/t_dist_contributors.pl diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 1b6662ea0..2b903aa88 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -10,11 +10,11 @@ on: jobs: format: - runs-on: ubuntu-20.04 - name: Ubuntu 20.04 | format + runs-on: ubuntu-22.04 + name: Ubuntu 22.04 | format env: CI_OS_NAME: linux - CI_RUNS_ON: ubuntu-20.04 + CI_RUNS_ON: ubuntu-22.04 CI_COMMIT: ${{ github.sha }} CI_M32: 0 steps: @@ -27,14 +27,14 @@ jobs: CI_BUILD_STAGE_NAME: build run: | bash ci/ci-install.bash && - sudo apt-get install clang-format-11 yapf3 && + sudo apt-get install clang-format-14 yapf3 && git config --global user.email "action@example.com" && git config --global user.name "github action" - name: Format code run: | autoconf && ./configure && - make -j 2 format CLANGFORMAT=clang-format-11 && + make -j 2 format CLANGFORMAT=clang-format-14 && git status - name: Push run: | diff --git a/.gitignore b/.gitignore index 2bfa23d4b..48859af2b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ \#* .#* +.gdb_history .nfs* *~ *.tidy diff --git a/Changes b/Changes index 98f97de74..06ce093d1 100644 --- a/Changes +++ b/Changes @@ -8,6 +8,31 @@ The changes in each Verilator version are described below. The contributors that suggested a given feature are shown in []. Thanks! +Verilator 4.228 2022-10-01 +========================== + +**Announcement:** + +* The next release is anticipated primere Verilator Version 5. Please + consider beta-testing the github 'develop-v5' branch, which will soon + merge into the github 'master' branch (#3383). + +**Minor:** + +* Support some IEEE signal strengths (#3601) (#3629). [Ryszard Rozak/Antmicro] +* Add --main to generate main() C++ (previously was experimental only). +* Add --build-jobs, and rework arguments for -j (#3623). [Kamil Rakoczy] +* Rename --bin to --build-dep-bin. +* Rename debug flags --dumpi-tree, --dumpi-graph, etc. [Geza Lore] +* Fix thread saftey in SystemC VL_ASSIGN_SBW/WSB (#3494) (#3513). [Mladen Slijepcevic] +* Fix crash in gate optimization of circular logic (#3543). [Bill Flynn] +* Fix arguments in non-static method call (#3547) (#3582). [Gustav Svensk] +* Fix default --mod-prefix when --prefix is repeated (#3603). [Geza Lore] +* Fix calling trace() after open() segfault (#3610) (#3627). [Yu-Sheng Lin] +* Fix typedef'ed class conversion to boolean (#3616). [Aleksander Kiryk] +* Fix Verilation speed when disabled warnings (#3632). [Kamil Rakoczy/Antmicro] + + Verilator 4.226 2022-08-31 ========================== @@ -20,12 +45,13 @@ Verilator 4.226 2022-08-31 * Support $test$plusargs(expr) (#3489). * Rename trace rolloverSize() (#3570). * Improve Verilation speed with --threads on large designs. [Geza Lore] +* Improve Verilation memory by reducing V3Number (#3521). [Mariusz Glebocki/Antmicro] * Fix struct pattern assignment (#2328) (#3517). [Mostafa Gamal] * Fix public combo propagation issues (#2905). [Todd Strader] * Fix incorrect tristate logic (#3399) [shareefj, Vighnesh Iyer] * Fix incorrect bit op tree optimization (#3470). [algrobman] * Fix bisonpre for MSYS2 (#3471). -* Fix max memory usage (#3483). [Kamil Rakoczy] +* Fix max memory usage (#3483). [Kamil Rakoczy/Antmicro] * Fix empty string arguments to display (#3484). [Grulfen] * Fix table misoptimizing away display (#3488). [Stefan Post] * Fix unique_ptr memory header for MinGW64 (#3493). @@ -36,7 +62,7 @@ Verilator 4.226 2022-08-31 * Fix segfault exporting non-existant package (#3535). * Fix void-cast queue pop_front or pop_back (#3542) (#3364). [Drew Ranck] * Fix case statement comparing string literal (#3544). [Gustav Svensk] -* Fix === with some tristate constants (#3551). [Ryszard Rozak] +* Fix === with some tristate constants (#3551). [Ryszard Rozak/Antmicro] * Fix converting subclasses to string (#3552). [Arkadiusz Kozdra/Antmicro] * Fix --hierarchical with order-based pin connections (#3583) (#3585). [Kelin9298] diff --git a/Makefile.in b/Makefile.in index fc9b6b1a9..662a57361 100644 --- a/Makefile.in +++ b/Makefile.in @@ -346,13 +346,13 @@ analyzer-include: format: clang-format yapf format-pl-exec -CLANGFORMAT = clang-format-11 +CLANGFORMAT = clang-format-14 CLANGFORMAT_FLAGS = -i CLANGFORMAT_FILES = $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL) test_regress/t/*.c* test_regress/t/*.h clang-format: - @$(CLANGFORMAT) --version | egrep 11.0 > /dev/null \ - || echo "*** You are not using clang-format 11.0, indents may differ from master's ***" + @$(CLANGFORMAT) --version | egrep 14.0 > /dev/null \ + || echo "*** You are not using clang-format-14, indents may differ from master's ***" $(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CLANGFORMAT_FILES) PY_PROGRAMS = \ @@ -391,10 +391,10 @@ yapf: FLAKE8 = flake8 FLAKE8_FLAGS = \ --extend-exclude=fastcov.py \ - --ignore=E123,E129,E251,E501,W503,W504,E701 + --ignore=E123,E129,E251,E402,E501,W503,W504,E701 PYLINT = pylint -PYLINT_FLAGS = --disable=R0801 +PYLINT_FLAGS = --score=n --disable=R0801 lint-py: -$(FLAKE8) $(FLAKE8_FLAGS) $(PY_PROGRAMS) diff --git a/README.rst b/README.rst index 8dd636245..d46296d02 100644 --- a/README.rst +++ b/README.rst @@ -28,7 +28,7 @@ Welcome to Verilator - |Logo| * - |verilator multithreaded performance| - **Fast** - * Outperforms many commercial simulators + * Outperforms many closed-source commercial simulators * Single- and multi-threaded output models * - **Widely Used** * Wide industry and academic deployment @@ -55,20 +55,19 @@ performing lint checks, and optionally inserting assertion checks and coverage-analysis points. It outputs single- or multi-threaded .cpp and .h files, the "Verilated" code. -The user writes a little C++/SystemC wrapper file, which instantiates the -"Verilated" model of the user's top level module. These C++/SystemC files -are then compiled by a C++ compiler (gcc/clang/MSVC++). Executing the -resulting executable performs the design simulation. Verilator also -supports linking Verilated generated libraries, optionally encrypted, into -other simulators. +These Verilated C++/SystemC files are then compiled by a C++ compiler +(gcc/clang/MSVC++), optionally along with a user's own C++/SystemC wrapper +file to instantiate the Verilated model. Executing the resulting executable +performs the design simulation. Verilator also supports linking Verilated +generated libraries, optionally encrypted, into other simulators. Verilator may not be the best choice if you are expecting a full featured -replacement for Incisive, ModelSim/Questa, VCS or another commercial -Verilog simulator, or if you are looking for a behavioral Verilog simulator -e.g. for a quick class project (we recommend `Icarus Verilog`_ for this.) -However, if you are looking for a path to migrate SystemVerilog to C++ or -SystemC, or your team is comfortable writing just a touch of C++ code, -Verilator is the tool for you. +replacement for a closed-source Verilog simulator, need SDF annotation, +mixed-signal simulation, or are doing a quick class project (we recommend +`Icarus Verilog`_ for classwork.) However, if you are looking for a path +to migrate SystemVerilog to C++/SystemC, or want high speed simulation of +synthesizable designs containing limited verification constructs, Verilator +is the tool for you. Performance @@ -85,9 +84,11 @@ multithreading (yielding 200-1000x total over interpreted simulators). Verilator has typically similar or better performance versus the closed-source Verilog simulators (Carbon Design Systems Carbonator, -Modelsim, Cadence Incisive/NC-Verilog, Synopsys VCS, VTOC, and Pragmatic -CVer/CVC). But, Verilator is open-sourced, so you can spend on computes -rather than licenses. Thus Verilator gives you the best cycles/dollar. +Modelsim/Questa, Cadence Incisive/NC-Verilog, Synopsys VCS, VTOC, and +Pragmatic CVer/CVC). But, Verilator is open-sourced, so you can spend on +computes rather than licenses. Thus Verilator gives you the best +cycles/dollar. + Installation & Documentation ============================ diff --git a/bin/verilator b/bin/verilator index 62f7be232..4c9e08209 100755 --- a/bin/verilator +++ b/bin/verilator @@ -282,8 +282,9 @@ detailed descriptions of these arguments. --autoflush Flush streams after all $displays --bbox-sys Blackbox unknown $system calls --bbox-unsup Blackbox unsupported language features - --bin Override Verilator binary --build Build model executable/library after Verilation + --build-dep-bin Override build dependency Verilator binary + --build-jobs Parallelism for --build --cc Create C++ output --cdc Clock domain crossing analysis -CFLAGS C++ compiler arguments for makefile @@ -308,10 +309,13 @@ detailed descriptions of these arguments. +define+= Set preprocessor define --dpi-hdr-only Only produce the DPI header file --dump-defines Show preprocessor defines with -E - --dump-tree Enable dumping .tree files + --dump-graph Enable dumping V3Graphs to .dot + --dump-tree Enable dumping Ast .tree files --dump-tree-addrids Use short identifiers instead of addresses - --dump-treei Enable dumping .tree files at a level - --dump-treei- Enable dumping .tree file at a source file at a level + --dump- Enable dumping everything in source file + --dumpi-graph Enable dumping V3Graphs to .dot files at level + --dumpi-tree Enable dumping Ast .tree files at level + --dumpi- Enable dumping everything in source file at level -E Preprocess, but do not compile --error-limit Abort after this number of errors --exe Link to create executable @@ -334,7 +338,7 @@ detailed descriptions of these arguments. +incdir+ Directory to search for includes --inline-mult Tune module inlining --instr-count-dpi Assumed dynamic instruction count of DPI imports - -j Parallelism for --build + -j Parallelism for --build (alias to --build-jobs) --l2-name Verilog scope name of the top module --language Default language standard to parse -LDFLAGS Linker pre-object arguments for makefile @@ -343,6 +347,7 @@ detailed descriptions of these arguments. --lint-only Lint, but do not make output --make Generate scripts for specified build tool -MAKEFLAGS Arguments to pass to make during --build + --main Generate C++ main() file --max-num-width Maximum number width (default: 64K) --Mdir Name of output object directory --MMD Create .d dependency files @@ -354,6 +359,7 @@ detailed descriptions of these arguments. -O Selectable optimizations -o Name of final executable --no-order-clock-delay Disable ordering clock enable assignments + --no-verilate Skip Verilation, only compile previously Verilated code --output-split Split .cpp files into pieces --output-split-cfuncs Split model functions --output-split-ctrace Split tracing functions diff --git a/bin/verilator_difftree b/bin/verilator_difftree index 3e8315691..d7c65a28e 100755 --- a/bin/verilator_difftree +++ b/bin/verilator_difftree @@ -38,7 +38,7 @@ def diff_dir(a, b): anyfile = False for base in sorted(files.keys()): - if (not 'a' in files[base]) or (not 'b' in files[base]): + if ('a' not in files[base]) or ('b' not in files[base]): continue a = files[base]['a'] b = files[base]['b'] diff --git a/bin/verilator_gantt b/bin/verilator_gantt index 616af30dc..03a7a16af 100755 --- a/bin/verilator_gantt +++ b/bin/verilator_gantt @@ -149,7 +149,8 @@ def report(): for thread in Threads: # Make potentially multiple characters per column for start in Threads[thread]: - if not Threads[thread][start]: continue + if not Threads[thread][start]: + continue cpu = Threads[thread][start]['cpu'] elapsed = Threads[thread][start]['end'] - start if cpu not in Global['cpus']: diff --git a/ci/ci-install.bash b/ci/ci-install.bash index 4f61f06c4..2e7325cea 100755 --- a/ci/ci-install.bash +++ b/ci/ci-install.bash @@ -19,6 +19,10 @@ set -x cd $(dirname "$0")/.. +# Avoid occasional cpan failures "Issued certificate has expired." +export PERL_LWP_SSL_VERIFY_HOSTNAME=0 +echo "check_certificate = off" >> ~/.wgetrc + fatal() { echo "ERROR: $(basename "$0"): $1" >&2; exit 1; } diff --git a/ci/docker/buildenv/Dockerfile b/ci/docker/buildenv/Dockerfile index 7e6682357..7adf4b3d2 100644 --- a/ci/docker/buildenv/Dockerfile +++ b/ci/docker/buildenv/Dockerfile @@ -6,7 +6,7 @@ # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -FROM ubuntu:20.04 +FROM ubuntu:22.04 RUN apt-get update \ && DEBIAN_FRONTEND=noninteractive \ diff --git a/ci/docker/buildenv/README.rst b/ci/docker/buildenv/README.rst index 5e7110c84..3ff025fc9 100644 --- a/ci/docker/buildenv/README.rst +++ b/ci/docker/buildenv/README.rst @@ -8,7 +8,7 @@ Verilator build. It uses the following parameters: - Source revision (default: master) -- Compiler (GCC 9.3.0, clang 10.0.0, default: 9.3.0) +- Compiler (GCC 10.3.0, clang 10.0.0, default: 10.3.0) The container is published as ``verilator/verilator-buildenv`` on `docker hub diff --git a/ci/docker/run/Dockerfile b/ci/docker/run/Dockerfile index 18c40483f..fa5c98519 100644 --- a/ci/docker/run/Dockerfile +++ b/ci/docker/run/Dockerfile @@ -6,7 +6,7 @@ # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -FROM ubuntu:20.04 +FROM ubuntu:22.04 RUN apt-get update \ && DEBIAN_FRONTEND=noninteractive \ diff --git a/configure.ac b/configure.ac index c7ef7c1be..35b3fcd01 100644 --- a/configure.ac +++ b/configure.ac @@ -10,7 +10,7 @@ # Then 'make maintainer-dist' #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[4.226 2022-08-31], +AC_INIT([Verilator],[4.228 2022-10-01], [https://verilator.org], [verilator],[https://verilator.org]) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 9c10dbb6f..0c3be357f 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -44,6 +44,7 @@ HyungKi Jeong Iru Cai Ivan Vnučec Iztok Jeras +Jake Merdich James Hanlon James Hutchinson James Pallister @@ -82,6 +83,7 @@ Michael Killough Michaël Lefebvre Mike Popoloski Miodrag Milanović +Mladen Slijepcevic Morten Borup Petersen Mostafa Gamal Nandu Raj @@ -89,6 +91,7 @@ Nathan Kohagen Nathan Myers Patrick Stewart Paul Wright +Pawel Sagan Peter Horvath Peter Monsson Philipp Wagner @@ -128,5 +131,6 @@ Yoda Lee Yossi Nivin Yuri Victorovich Yutetsu TAKATSUKASA +Yu-Sheng Lin Yves Mathieu Zhanglei Wang diff --git a/docs/guide/conf.py b/docs/guide/conf.py index 0714e50c7..fb9c66d1a 100644 --- a/docs/guide/conf.py +++ b/docs/guide/conf.py @@ -13,6 +13,7 @@ from datetime import datetime import os import re import sys + sys.path.insert(0, os.path.abspath('./_ext')) import sphinx_rtd_theme # pylint: disable=wrong-import-position, diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index 0348c4db2..a54510df4 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -115,13 +115,6 @@ Summary: Using this argument will likely cause incorrect simulation. -.. option:: --bin - - Rarely needed. Override the default filename for Verilator itself. - When a dependency (.d) file is created, this filename will become a - source dependency, such that a change in this binary will have make - rebuild the output files. - .. option:: --build After generating the SystemC/C++ code, Verilator will invoke the @@ -129,6 +122,24 @@ Summary: is also used). Verilator manages the build itself, and for this --build requires GNU Make to be available on the platform. +.. option:: --build-dep-bin + + Rarely needed. When a dependency (.d) file is created, this filename + will become a source dependency, such that a change in this binary will + have make rebuild the output files. Defaults to the full path to the + Verilator binary. + + This option was named `--bin` prior to version 4.228. + +.. option:: --build-jobs [] + + Specify the level of parallelism for :vlopt:`--build`. If zero, uses the + number of threads in the current hardware. Otherwise, the must + be a positive integer specifying the maximum number of parallel build + jobs. + + See also :vlopt:`-j`. + .. option:: --cc Specifies C++ without SystemC output mode; see also :vlopt:`--sc` @@ -255,8 +266,8 @@ Summary: generally is a less-optimized binary with symbols present (so GDB can be used on it). * Enable debugging messages (equivalent to :vlopt:`--debugi 3 <--debugi>`). * Enable internal assertions (equivalent to :vlopt:`--debug-check`). - * Enable intermediate form dump files (equivalent to :vlopt:`--dump-treei 3 - <--dump-treei>`). + * Enable intermediate form dump files (equivalent to :vlopt:`--dumpi-tree 3 + <--dumpi-tree>`). * Leak to make node numbers unique (equivalent to :vlopt:`--debug-leak <--no-debug-leak>`. * Call abort() instead of exit() if there are any errors (so GDB can see @@ -347,26 +358,21 @@ Summary: touch foo.v ; verilator -E --dump-defines foo.v +.. option:: --dump-graph + + Rarely needed. Enable dumping V3Graph .dot debug files with dumping + level 3. Before Verilator 4.228, :vlopt:`--dump-tree` used + to include this option. + .. option:: --dump-tree - Rarely needed. Enable writing .tree debug files with dumping level 3, + Rarely needed. Enable dumping Ast .tree debug files with dumping level 3, which dumps the standard critical stages. For details on the format see the Verilator Internals manual. :vlopt:`--dump-tree` is enabled automatically with :vlopt:`--debug`, so :vlopt:`--debug --no-dump-tree <--dump-tree>` may be useful if the dump files are large and not desired. -.. option:: --dump-treei - -.. option:: --dump-treei- - - Rarely needed - for developer use. Set internal tree dumping level - globally to a specific dumping level or set the specified Verilator - source file to the specified tree dumping level (e.g. - :vlopt:`--dump-treei-V3Order 9 <--dump-treei>`). Level 0 disables dumps - and is equivalent to :vlopt:`--no-dump-tree <--dump-tree>`. Level 9 - enables dumping of every stage. - .. option:: --dump-tree-addrids Rarely needed - for developer use. Replace AST node addresses with @@ -376,6 +382,28 @@ Summary: by a newly allocated node after a node with the same address has been dumped then freed. +.. option:: --dump- + + Rarely needed - for developer use. Enable all dumping in the given + source file at level 3. + +.. option:: --dumpi-graph + + Rarely needed - for developer use. Set internal V3Graph dumping level + globally to the specified value. + +.. option:: --dumpi-tree + + Rarely needed - for developer use. Set internal Ast dumping level + globally to the specified value. + +.. option:: --dumpi- + + Rarely needed - for developer use. Set the dumping level in the + specified Verilator source file to the specified value (e.g. + :vlopt:`--dumpi-V3Order 9`). Level 0 disables dumps and is equivalent + to :vlopt:`--no-dump-`. Level 9 enables dumping of everything. + .. option:: -E Preprocess the source code, but do not compile, similar to C++ @@ -615,11 +643,10 @@ Summary: .. option:: -j [] - Specify the level of parallelism for :vlopt:`--build`. The must - be a positive integer specifying the maximum number of parallel build - jobs, or can be omitted. When is omitted, the build will not try - to limit the number of parallel build jobs but attempt to execute all - independent build steps in parallel. + Specify the level of parallelism for :vlopt:`--build` if + :vlopt:`--build-jobs` isn't provided. If zero, uses the number of threads + in the current hardware. Otherwise, the must be a positive + integer specifying the maximum number of parallel build jobs. .. option:: --l2-name @@ -709,6 +736,15 @@ Summary: (e.g. ``-MAKEFLAGS -l -MAKEFLAGS -k``). Use of this option should not be required for simple builds using the host toolchain. +.. option:: --main + + Generates a top-level C++ main() file that supports parsing arguments, + but does not drive any inputs. This is sufficient to use for top-level + SystemVerilog designs that has no inputs, and does not need the C++ to + do any time advancement. + + Implies :vlopt:`--cc` if no other output mode was provided. + .. option:: --max-num-width Set the maximum number literal width (e.g. in 1024'd22 this it the diff --git a/docs/guide/install.rst b/docs/guide/install.rst index b69517076..31d553094 100644 --- a/docs/guide/install.rst +++ b/docs/guide/install.rst @@ -124,7 +124,7 @@ Those developing Verilator itself may also want these (see internals.rst): :: - sudo apt-get install gdb graphviz cmake clang clang-format-11 gprof lcov + sudo apt-get install gdb graphviz cmake clang clang-format-14 gprof lcov sudo apt-get install yapf3 sudo pip3 install sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe cpan install Pod::Perldoc diff --git a/docs/guide/simulating.rst b/docs/guide/simulating.rst index 01dd7f844..7209a0a19 100644 --- a/docs/guide/simulating.rst +++ b/docs/guide/simulating.rst @@ -7,9 +7,9 @@ Simulating (Verilated-Model Runtime) ************************************ -This section describes items related to simulating, that using a Verilated -model's executable. For the runtime arguments to a simulated model, see -:ref:`Simulation Runtime Arguments`. +This section describes items related to simulating, that is, the use of a +Verilated model's executable. For the runtime arguments to a simulated +model, see :ref:`Simulation Runtime Arguments`. .. _Benchmarking & Optimization: diff --git a/docs/internals.rst b/docs/internals.rst index 499e0fa12..c62881026 100644 --- a/docs/internals.rst +++ b/docs/internals.rst @@ -96,10 +96,11 @@ this. Each ``AstNode`` has pointers to up to four children, accessed by the ``op1p`` through ``op4p`` methods. These methods are then abstracted in a specific Ast\* node class to a more specific name. For example with the -``AstIf`` node (for ``if`` statements), ``ifsp`` calls ``op2p`` to give the +``AstIf`` node (for ``if`` statements), ``thensp`` calls ``op2p`` to give the pointer to the AST for the "then" block, while ``elsesp`` calls ``op3p`` to give the pointer to the AST for the "else" block, or NULL if there is not -one. +one. These accessors are automatically generated by ``astgen`` after +parsing the ``@astgen`` directives in the specific ``AstNode`` subclasses. ``AstNode`` has the concept of a next and previous AST - for example the next and previous statements in a block. Pointers to the AST for these @@ -501,22 +502,99 @@ code: The ``astgen`` Script --------------------- -Some of the code implementing passes is extremely repetitive, and must be -implemented for each sub-class of ``AstNode``. However, while repetitive, -there is more variability than can be handled in C++ macros. +The ``astgen`` script is used to generate some of the repetitive C++ code +related to the ``AstNode`` type hierarchy. An example is the abstract ``visit`` +methods in ``VNVisitor``. There are other uses, please see the ``*__gen*`` +files in the bulid directories and the ``astgen`` script itself for details. A +description of the more advanced features of ``astgen`` are provided here. -In Verilator this is implemented by using a script, ``astgen`` to -pre-process the C++ code. For example in ``V3Const.cpp`` this is used to -implement the ``visit()`` functions for each binary operation using the -``TREEOP`` macro. -The original C source code is transformed into C code in the ``obj_opt`` +Generating ``AstNode`` members +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Some of the member s of ``AstNode`` sub-classes are generated by ``astgen``. +These are emitted as pre-processor macro definitions, which then need to be +added to the ``AstNode`` sub-classes they correspond to. Specifically ``class +AstFoo`` should contain an instance of ``ASTGEN_MEMBERS_Foo;`` at class scope. +The ``astgen`` script checks and errors if this is not present. The method +generated depends on whether the class is a concrete final class, or an +abstract ``AstNode*`` base-class, and on ``@astgen`` directives present in +comment sections in the body of the ``AstNode`` sub-class definitions. + + +List of ``@astgen`` directives +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``@astgen`` directives in comments contained in the body of ``AstNode`` +sub-class definitions are parsed and contribute to the code generated by +``astgen``. The general syntax is ``@astgen := ``, +where ```` determines what is being defined, and ```` is +a ```` dependent description of the definition. The list of +``@astgen`` directives is as follows: + + +``op`` operand directives +""""""""""""""""""""""""""""" + +The ``op1``, ``op2``, ``op3`` and ``op4`` directives are used to describe the +name and type of the up to 4 child operands of a node. The syntax of the +```` field is `` : ``, where ```` +will be used as the base name of the generated operand accessors, and +```` is one of: + +1. An ``AstNode`` sub-class, defining the operand to be of that type, always + no-null, and with an always null ``nextp()``. That is, the child node is + always present, and is a single ``AstNode`` (as opposed to a list). + +2. ``Optional[]``. This is just like in point 1 above, but + defines the child node to be optional, meaning it may be null. + +3. ``List[AstNode sub-class]`` describes a list operand, which means the child + node may have a non-null ``nextp()`` and in addition the child itself may be + null, representing an empty list. + + +An example of the full syntax of the directive is +``@astgen op1 := lhsp : AstNodeMath``. + +``astnode`` generates accessors for the child nodes based on these directives. +For non-list children, the names of the getter and setter both are that of the +given ````. For list type children, the getter is ````, +and instead of the setter, there an ``add`` method is generated +that appends new nodes (or lists of nodes) to the child list. + +``alias op`` operand alias directives +"""""""""""""""""""""""""""""""""""""""" + +If a super-class already defined a name and type for a child node using the +``op`` directive, but a more appropriate name exists in the context of a +sub-class, then the alias directive can be used to introduce an additional name +for the child node. The is ``alias op := `` where +```` is the new name. ``op`` must have been defined in some +super-class of the current node. + +Example: ``@astgen alias op1 := condp`` + + +Additional features of ``astgen`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In addition to generating ``AstNode`` members as described above, +``astgen`` is also use to handle some of the repetitive implementation code +that is still variable enough not to be handled in C++ macros. + +In particular, ``astgen`` is used to pre-process some of the C++ source +files. For example in ``V3Const.cpp``, it is used to implement the +``visit()`` functions for each binary operation using the ``TREEOP`` macro. + +The original C++ source code is transformed into C++ code in the ``obj_opt`` and ``obj_dbg`` sub-directories (the former for the optimized version of Verilator, the latter for the debug version). So for example ``V3Const.cpp`` into ``V3Const__gen.cpp``. -Visitor Functions ----------------- +Visitor Functions +----------------- Verilator uses the "Visitor" design pattern to implement its refinement and optimization passes. This allows separation of the pass algorithm from the @@ -1153,8 +1231,9 @@ Generally what would you do to add a new feature? language and has a lot of back-and-forth with Verilator's grammar. Copy the appropriate rules to src/verilog.y and modify the productions. -4. If a new Ast type is needed, add it to V3AstNodes.h. Follow the - convention described above about the AstNode type hierarchy. +4. If a new Ast type is needed, add it to the appropriate V3AstNode*.h. + Follow the convention described above about the AstNode type hierarchy. + Ordering of definitions is enforced by ``astgen``. 5. Now you can run "test_regress/t/t_.pl --debug" and it'll probably fail but you'll see a diff --git a/examples/make_protect_lib/sim_main.cpp b/examples/make_protect_lib/sim_main.cpp index b3096b4c5..fefcb0c5a 100644 --- a/examples/make_protect_lib/sim_main.cpp +++ b/examples/make_protect_lib/sim_main.cpp @@ -32,7 +32,7 @@ int main(int argc, char** argv, char** env) { // When tracing, the contents of the secret module will not be seen VerilatedVcdC* tfp = nullptr; const char* flag = contextp->commandArgsPlusMatch("trace"); - if (flag && 0 == strcmp(flag, "+trace")) { + if (flag && 0 == std::strcmp(flag, "+trace")) { contextp->traceEverOn(true); VL_PRINTF("Enabling waves into logs/vlt_dump.vcd...\n"); tfp = new VerilatedVcdC; diff --git a/examples/make_tracing_sc/sc_main.cpp b/examples/make_tracing_sc/sc_main.cpp index 93861ceea..a23040a54 100644 --- a/examples/make_tracing_sc/sc_main.cpp +++ b/examples/make_tracing_sc/sc_main.cpp @@ -82,14 +82,14 @@ int sc_main(int argc, char* argv[]) { // You must do one evaluation before enabling waves, in order to allow // SystemC to interconnect everything for testing. - sc_start(1, SC_NS); + sc_start(SC_ZERO_TIME); #if VM_TRACE // If verilator was invoked with --trace argument, // and if at run time passed the +trace argument, turn on tracing VerilatedVcdSc* tfp = nullptr; const char* flag = Verilated::commandArgsPlusMatch("trace"); - if (flag && 0 == strcmp(flag, "+trace")) { + if (flag && 0 == std::strcmp(flag, "+trace")) { cout << "Enabling waves into logs/vlt_dump.vcd...\n"; tfp = new VerilatedVcdSc; top->trace(tfp, 99); // Trace 99 levels of hierarchy diff --git a/examples/xml_py/vl_file_copy b/examples/xml_py/vl_file_copy index 5eae927ed..1ff96328e 100755 --- a/examples/xml_py/vl_file_copy +++ b/examples/xml_py/vl_file_copy @@ -16,12 +16,13 @@ from shutil import copy2 class VlFileCopy: + def __init__( - self, - verilator_args, # presently all verilator options are passed-thru - # ideally this script would check against options mentioned in help + self, + verilator_args, # presently all verilator options are passed-thru + # ideally this script would check against options mentioned in help debug=0, - output_dir='copied'): # directory name we output file uses + output_dir='copied'): # directory name we output file uses self.debug = debug diff --git a/examples/xml_py/vl_hier_graph b/examples/xml_py/vl_hier_graph index 359bd5da2..566250226 100755 --- a/examples/xml_py/vl_hier_graph +++ b/examples/xml_py/vl_hier_graph @@ -14,12 +14,13 @@ import xml.etree.ElementTree as ET class VlHierGraph: + def __init__( - self, - verilator_args, # presently all verilator options are passed-thru - # ideally this script would check against options mentioned in help + self, + verilator_args, # presently all verilator options are passed-thru + # ideally this script would check against options mentioned in help debug=0, - output_filename='graph.dot'): # output filename + output_filename='graph.dot'): # output filename self.debug = debug self.next_vertex_number = 0 self.name_to_number = {} diff --git a/include/verilated.cpp b/include/verilated.cpp index ee5090507..1b5dab84b 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -1003,22 +1003,22 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA } } -static inline bool _vl_vsss_eof(FILE* fp, int floc) VL_MT_SAFE { +static bool _vl_vsss_eof(FILE* fp, int floc) VL_MT_SAFE { if (VL_LIKELY(fp)) { return std::feof(fp) ? true : false; // true : false to prevent MSVC++ warning } else { return floc < 0; } } -static inline void _vl_vsss_advance(FILE* fp, int& floc) VL_MT_SAFE { +static void _vl_vsss_advance(FILE* fp, int& floc) VL_MT_SAFE { if (VL_LIKELY(fp)) { std::fgetc(fp); } else { floc -= 8; } } -static inline int _vl_vsss_peek(FILE* fp, int& floc, const WDataInP fromp, - const std::string& fstr) VL_MT_SAFE { +static int _vl_vsss_peek(FILE* fp, int& floc, const WDataInP fromp, + const std::string& fstr) VL_MT_SAFE { // Get a character without advancing if (VL_LIKELY(fp)) { const int data = std::fgetc(fp); @@ -1035,17 +1035,16 @@ static inline int _vl_vsss_peek(FILE* fp, int& floc, const WDataInP fromp, } } } -static inline void _vl_vsss_skipspace(FILE* fp, int& floc, const WDataInP fromp, - const std::string& fstr) VL_MT_SAFE { +static void _vl_vsss_skipspace(FILE* fp, int& floc, const WDataInP fromp, + const std::string& fstr) VL_MT_SAFE { while (true) { const int c = _vl_vsss_peek(fp, floc, fromp, fstr); if (c == EOF || !std::isspace(c)) return; _vl_vsss_advance(fp, floc); } } -static inline void _vl_vsss_read_str(FILE* fp, int& floc, const WDataInP fromp, - const std::string& fstr, char* tmpp, - const char* acceptp) VL_MT_SAFE { +static void _vl_vsss_read_str(FILE* fp, int& floc, const WDataInP fromp, const std::string& fstr, + char* tmpp, const char* acceptp) VL_MT_SAFE { // Read into tmp, consisting of characters from acceptp list char* cp = tmpp; while (true) { @@ -1059,9 +1058,8 @@ static inline void _vl_vsss_read_str(FILE* fp, int& floc, const WDataInP fromp, *cp++ = '\0'; // VL_DBG_MSGF(" _read got='"<>= 1) { VL_ASSIGNBIT_WI(lsb, owp, ld & 1); } } -static inline void _vl_vsss_based(WDataOutP owp, int obits, int baseLog2, const char* strp, - size_t posstart, size_t posend) VL_MT_SAFE { +static void _vl_vsss_based(WDataOutP owp, int obits, int baseLog2, const char* strp, + size_t posstart, size_t posend) VL_MT_SAFE { // Read in base "2^^baseLog2" digits from strp[posstart..posend-1] into owp of size obits. int lsb = 0; for (int i = 0, pos = static_cast(posend) - 1; diff --git a/include/verilated.h b/include/verilated.h index 5700e67be..ed7f7955a 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -274,7 +274,7 @@ protected: public: /// Returns the VerilatedContext this model is instantiated under /// Used to get to e.g. simulation time via contextp()->time() - inline VerilatedContext* contextp() const { return &m_context; } + VerilatedContext* contextp() const { return &m_context; } /// Returns the hierarchical name of this module instance. virtual const char* hierName() const = 0; /// Returns the name of this model (the name of the generated model class). @@ -457,9 +457,9 @@ public: VerilatedCovContext* coveragep() VL_MT_SAFE; /// Set debug level /// Debug is currently global, but for forward compatibility have a per-context method - static void debug(int val) VL_MT_SAFE; + static inline void debug(int val) VL_MT_SAFE; /// Return debug level - static int debug() VL_MT_SAFE; + static inline int debug() VL_MT_SAFE; /// Set current number of errors/assertions void errorCount(int val) VL_MT_SAFE; /// Increment current number of errors/assertions @@ -521,7 +521,7 @@ public: /// /// * Else, time comes from the legacy 'double sc_time_stamp()' which /// must be a function defined by the user's wrapper. - uint64_t time() const VL_MT_SAFE; + inline uint64_t time() const VL_MT_SAFE; /// Set current simulation time. See time() for side effect details void time(uint64_t value) VL_MT_SAFE { m_s.m_time = value; } /// Advance current simulation time. See time() for side effect details @@ -652,13 +652,13 @@ public: // But internals only - called from VerilatedModule's const char* name() const { return m_namep; } const char* identifier() const { return m_identifierp; } int8_t timeunit() const { return m_timeunit; } - inline VerilatedSyms* symsp() const { return m_symsp; } + VerilatedSyms* symsp() const { return m_symsp; } VerilatedVar* varFind(const char* namep) const VL_MT_SAFE_POSTINIT; VerilatedVarNameMap* varsp() const VL_MT_SAFE_POSTINIT { return m_varsp; } void scopeDump() const; void* exportFindError(int funcnum) const; static void* exportFindNullError(int funcnum) VL_MT_SAFE; - static inline void* exportFind(const VerilatedScope* scopep, int funcnum) VL_MT_SAFE { + static void* exportFind(const VerilatedScope* scopep, int funcnum) VL_MT_SAFE { if (VL_UNLIKELY(!scopep)) return exportFindNullError(funcnum); if (VL_LIKELY(funcnum < scopep->m_funcnumMax)) { // m_callbacksp must be declared, as Max'es are > 0 @@ -727,7 +727,7 @@ public: /// Return debug level /// When multithreaded this may not immediately react to another thread /// changing the level (no mutex) - static inline int debug() VL_MT_SAFE { return s_debug; } + static int debug() VL_MT_SAFE { return s_debug; } #else /// Return constant 0 debug level, so C++'s optimizer rips up static constexpr int debug() VL_PURE { return 0; } @@ -933,8 +933,8 @@ private: #endif }; -inline void VerilatedContext::debug(int val) VL_MT_SAFE { Verilated::debug(val); } -inline int VerilatedContext::debug() VL_MT_SAFE { return Verilated::debug(); } +void VerilatedContext::debug(int val) VL_MT_SAFE { Verilated::debug(val); } +int VerilatedContext::debug() VL_MT_SAFE { return Verilated::debug(); } //========================================================================= // Data Types diff --git a/include/verilated_dpi.cpp b/include/verilated_dpi.cpp index caa72af85..7f68e1bad 100644 --- a/include/verilated_dpi.cpp +++ b/include/verilated_dpi.cpp @@ -181,7 +181,7 @@ void svPutPartselLogic(svLogicVecVal* dp, const svLogicVecVal s, int lbit, int w //====================================================================== // Open array internals -static inline const VerilatedDpiOpenVar* _vl_openhandle_varp(const svOpenArrayHandle h) { +static const VerilatedDpiOpenVar* _vl_openhandle_varp(const svOpenArrayHandle h) { if (VL_UNLIKELY(!h)) { VL_FATAL_MT(__FILE__, __LINE__, "", "%%Error: DPI svOpenArrayHandle function called with nullptr handle"); diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index 73c821a60..8b33b4855 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -161,13 +161,13 @@ class VerilatedFstBuffer VL_NOT_FINAL { // Implementations of duck-typed methods for VerilatedTraceBuffer. These are // called from only one place (the full* methods), so always inline them. - VL_ATTR_ALWINLINE inline void emitBit(uint32_t code, CData newval); - VL_ATTR_ALWINLINE inline void emitCData(uint32_t code, CData newval, int bits); - VL_ATTR_ALWINLINE inline void emitSData(uint32_t code, SData newval, int bits); - VL_ATTR_ALWINLINE inline void emitIData(uint32_t code, IData newval, int bits); - VL_ATTR_ALWINLINE inline void emitQData(uint32_t code, QData newval, int bits); - VL_ATTR_ALWINLINE inline void emitWData(uint32_t code, const WData* newvalp, int bits); - VL_ATTR_ALWINLINE inline void emitDouble(uint32_t code, double newval); + VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval); + VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits); + VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits); + VL_ATTR_ALWINLINE void emitIData(uint32_t code, IData newval, int bits); + VL_ATTR_ALWINLINE void emitQData(uint32_t code, QData newval, int bits); + VL_ATTR_ALWINLINE void emitWData(uint32_t code, const WData* newvalp, int bits); + VL_ATTR_ALWINLINE void emitDouble(uint32_t code, double newval); }; //============================================================================= @@ -232,7 +232,7 @@ public: } // Internal class access - inline VerilatedFst* spTrace() { return &m_sptrace; } + VerilatedFst* spTrace() { return &m_sptrace; } }; #endif // guard diff --git a/include/verilated_fst_sc.h b/include/verilated_fst_sc.h index ae0943d8b..f5aaa305c 100644 --- a/include/verilated_fst_sc.h +++ b/include/verilated_fst_sc.h @@ -52,35 +52,35 @@ public: } spTrace()->set_time_resolution(sc_get_time_resolution().to_string()); } - virtual ~VerilatedFstSc() /*override*/ { close(); } + ~VerilatedFstSc() override { close(); } // METHODS /// Called by SystemC simulate() - virtual void cycle(bool delta_cycle) { + void cycle(bool delta_cycle) override { if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); } } // Override VerilatedFstC. Must be called after starting simulation. - // cppcheck-suppress missingOverride // GCC won't accept override - virtual void open(const char* filename) /*override*/ VL_MT_SAFE; + // Note: this is not a virtual function in the base class, so no 'override' + virtual void open(const char* filename) VL_MT_SAFE; private: /// Fake outs for linker #ifdef NC_SYSTEMC // Cadence Incisive has these as abstract functions so we must create them - virtual void set_time_unit(int exponent10_seconds) {} // deprecated + void set_time_unit(int exponent10_seconds) override {} // deprecated #endif - virtual void set_time_unit(double v, sc_time_unit tu) {} // LCOV_EXCL_LINE + void set_time_unit(double v, sc_time_unit tu) override {} // LCOV_EXCL_LINE //-------------------------------------------------- // SystemC 2.1.v1 -#define DECL_TRACE_METHOD_A(tp) virtual void trace(const tp& object, const std::string& name); +#define DECL_TRACE_METHOD_A(tp) void trace(const tp& object, const std::string& name) override; #define DECL_TRACE_METHOD_B(tp) \ - virtual void trace(const tp& object, const std::string& name, int width); + void trace(const tp& object, const std::string& name, int width) override; - virtual void write_comment(const std::string&); - virtual void trace(const unsigned int&, const std::string&, const char**); + void write_comment(const std::string&) override; + void trace(const unsigned int&, const std::string&, const char**) override; // clang-format off // Formatting matches that of sc_trace.h diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index a7c3fcc73..8f5027f96 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -282,7 +282,7 @@ inline uint64_t vl_time_stamp64() { # endif #endif -inline uint64_t VerilatedContext::time() const VL_MT_SAFE { +uint64_t VerilatedContext::time() const VL_MT_SAFE { // When using non-default context, fastest path is return time if (VL_LIKELY(m_s.m_time)) return m_s.m_time; #if defined(SYSTEMC_VERSION) || (!defined(VL_TIME_CONTEXT) && !defined(VL_NO_LEGACY)) @@ -448,10 +448,17 @@ static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE { { \ const int words = VL_WORDS_I(obits); \ sc_biguint<(obits)> _butemp = (svar).read(); \ - for (int i = 0; i < words; ++i) { \ - int msb = ((i + 1) * VL_IDATASIZE) - 1; \ - msb = (msb >= (obits)) ? ((obits)-1) : msb; \ - (owp)[i] = _butemp.range(msb, i * VL_IDATASIZE).to_uint(); \ + uint32_t* chunk = _butemp.get_raw(); \ + int32_t lsb = 0; \ + while (lsb < obits - BITS_PER_DIGIT) { \ + const uint32_t data = *chunk; \ + ++chunk; \ + _vl_insert_WI(owp.data(), data, lsb + BITS_PER_DIGIT - 1, lsb); \ + lsb += BITS_PER_DIGIT; \ + } \ + if (lsb < obits) { \ + const uint32_t msb_data = *chunk; \ + _vl_insert_WI(owp.data(), msb_data, obits - 1, lsb); \ } \ (owp)[words - 1] &= VL_MASK_E(obits); \ } @@ -492,13 +499,23 @@ static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE { { (svar).write(rd); } #define VL_ASSIGN_SBQ(obits, svar, rd) \ { (svar).write(rd); } +#define VL_SC_BITS_PER_DIGIT 30 // This comes from sc_nbdefs.h BITS_PER_DIGIT #define VL_ASSIGN_SBW(obits, svar, rwp) \ { \ sc_biguint<(obits)> _butemp; \ - for (int i = 0; i < VL_WORDS_I(obits); ++i) { \ - int msb = ((i + 1) * VL_IDATASIZE) - 1; \ - msb = (msb >= (obits)) ? ((obits)-1) : msb; \ - _butemp.range(msb, i* VL_IDATASIZE) = (rwp)[i]; \ + int32_t lsb = 0; \ + uint32_t* chunk = _butemp.get_raw(); \ + while (lsb + VL_SC_BITS_PER_DIGIT < (obits)) { \ + static_assert(std::is_same::value, "IData and EData missmatch"); \ + const uint32_t data = VL_SEL_IWII(lsb + VL_SC_BITS_PER_DIGIT + 1, (rwp).data(), lsb, \ + VL_SC_BITS_PER_DIGIT); \ + *chunk = data & VL_MASK_E(VL_SC_BITS_PER_DIGIT); \ + ++chunk; \ + lsb += VL_SC_BITS_PER_DIGIT; \ + } \ + if (lsb < (obits)) { \ + const uint32_t msb_data = VL_SEL_IWII((obits) + 1, (rwp).data(), lsb, (obits)-lsb); \ + *chunk = msb_data & VL_MASK_E((obits)-lsb); \ } \ (svar).write(_butemp); \ } diff --git a/include/verilated_imp.h b/include/verilated_imp.h index d55c7b228..cc1971d04 100644 --- a/include/verilated_imp.h +++ b/include/verilated_imp.h @@ -356,7 +356,7 @@ public: // But only for verilated*.cpp } } } - inline FILE* fdToFp(IData fdi) VL_MT_SAFE_EXCLUDES(m_fdMutex) { + FILE* fdToFp(IData fdi) VL_MT_SAFE_EXCLUDES(m_fdMutex) { const VerilatedLockGuard lock{m_fdMutex}; const VerilatedFpList fdlist = fdToFpList(fdi); if (VL_UNLIKELY(fdlist.size() != 1)) return nullptr; @@ -466,7 +466,7 @@ public: // There's often many more scopes than userdata's and thus having a ~48byte // per map overhead * N scopes would take much more space and cache thrashing. // As scopep's are pointers, this implicitly handles multiple Context's - static inline void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE { + static void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE { const VerilatedLockGuard lock{s().m_userMapMutex}; const auto it = s().m_userMap.find(std::make_pair(scopep, userKey)); if (it != s().m_userMap.end()) { @@ -475,7 +475,7 @@ public: s().m_userMap.emplace(std::make_pair(scopep, userKey), userData); } } - static inline void* userFind(const void* scopep, void* userKey) VL_MT_SAFE { + static void* userFind(const void* scopep, void* userKey) VL_MT_SAFE { const VerilatedLockGuard lock{s().m_userMapMutex}; const auto& it = vlstd::as_const(s().m_userMap).find(std::make_pair(scopep, userKey)); if (VL_UNLIKELY(it == s().m_userMap.end())) return nullptr; diff --git a/include/verilated_profiler.h b/include/verilated_profiler.h index a237ee5cf..5ddf3b0d9 100644 --- a/include/verilated_profiler.h +++ b/include/verilated_profiler.h @@ -45,8 +45,7 @@ class VlThreadPool; //============================================================================= // Return high-precision counter for profiling, or 0x0 if not available -VL_ATTR_ALWINLINE -inline QData VL_CPU_TICK() { +VL_ATTR_ALWINLINE QData VL_CPU_TICK() { uint64_t val; VL_GET_CPU_TICK(val); return val; @@ -171,9 +170,9 @@ public: // METHODS // Is profiling enabled - inline bool enabled() const { return m_enabled; } + bool enabled() const { return m_enabled; } // Append a trace record to the trace buffer of the current thread - static inline VlExecutionRecord& addRecord() { + static VlExecutionRecord& addRecord() { t_trace.emplace_back(); return t_trace.back(); } diff --git a/include/verilated_threads.h b/include/verilated_threads.h index 59658bf20..b595c1bca 100644 --- a/include/verilated_threads.h +++ b/include/verilated_threads.h @@ -103,7 +103,7 @@ public: // Upstream mtasks must call this when they complete. // Returns true when the current MTaskVertex becomes ready to execute, // false while it's still waiting on more dependencies. - inline bool signalUpstreamDone(bool evenCycle) { + bool signalUpstreamDone(bool evenCycle) { if (evenCycle) { const uint32_t upstreamDepsDone = 1 + m_upstreamDepsDone.fetch_add(1, std::memory_order_release); @@ -116,11 +116,11 @@ public: return (upstreamDepsDone_prev == 1); } } - inline bool areUpstreamDepsDone(bool evenCycle) const { + bool areUpstreamDepsDone(bool evenCycle) const { const uint32_t target = evenCycle ? m_upstreamDepCount : 0; return m_upstreamDepsDone.load(std::memory_order_acquire) == target; } - inline void waitUntilUpstreamDone(bool evenCycle) const { + void waitUntilUpstreamDone(bool evenCycle) const { unsigned ct = 0; while (VL_UNLIKELY(!areUpstreamDepsDone(evenCycle))) { VL_CPU_RELAX(); @@ -171,7 +171,7 @@ public: // METHODS template - inline void dequeWork(ExecRec* workp) VL_MT_SAFE_EXCLUDES(m_mutex) { + void dequeWork(ExecRec* workp) VL_MT_SAFE_EXCLUDES(m_mutex) { // Spin for a while, waiting for new data if VL_CONSTEXPR_CXX17 (SpinWait) { for (unsigned i = 0; i < VL_LOCK_SPINS; ++i) { @@ -191,7 +191,7 @@ public: m_ready.erase(m_ready.begin()); m_ready_size.fetch_sub(1, std::memory_order_relaxed); } - inline void addTask(VlExecFnp fnp, VlSelfP selfp, bool evenCycle = false) + void addTask(VlExecFnp fnp, VlSelfP selfp, bool evenCycle = false) VL_MT_SAFE_EXCLUDES(m_mutex) { bool notify; { @@ -223,8 +223,8 @@ public: ~VlThreadPool() override; // METHODS - inline int numThreads() const { return m_workers.size(); } - inline VlWorkerThread* workerp(int index) { + int numThreads() const { return m_workers.size(); } + VlWorkerThread* workerp(int index) { assert(index >= 0); assert(index < m_workers.size()); return m_workers[index]; diff --git a/include/verilated_trace.h b/include/verilated_trace.h index 03ca2ba2c..151d2c9f2 100644 --- a/include/verilated_trace.h +++ b/include/verilated_trace.h @@ -318,8 +318,8 @@ protected: void flushBase(); #ifdef VL_THREADED - inline bool offload() const { return m_offload; } - inline bool parallel() const { return m_parallel; } + bool offload() const { return m_offload; } + bool parallel() const { return m_parallel; } #else static constexpr bool offload() { return false; } static constexpr bool parallel() { return false; } @@ -425,7 +425,7 @@ public: // duck-typed void emitWData(uint32_t code, const WData* newvalp, int bits) = 0; // duck-typed void emitDouble(uint32_t code, double newval) = 0; - VL_ATTR_ALWINLINE inline uint32_t* oldp(uint32_t code) { return m_sigs_oldvalp + code; } + VL_ATTR_ALWINLINE uint32_t* oldp(uint32_t code) { return m_sigs_oldvalp + code; } // Write to previous value buffer value and emit trace entry. void fullBit(uint32_t* oldp, CData newval); @@ -441,27 +441,27 @@ public: // thread and are called chg*Impl // Check previous dumped value of signal. If changed, then emit trace entry - VL_ATTR_ALWINLINE inline void chgBit(uint32_t* oldp, CData newval) { + VL_ATTR_ALWINLINE void chgBit(uint32_t* oldp, CData newval) { const uint32_t diff = *oldp ^ newval; if (VL_UNLIKELY(diff)) fullBit(oldp, newval); } - VL_ATTR_ALWINLINE inline void chgCData(uint32_t* oldp, CData newval, int bits) { + VL_ATTR_ALWINLINE void chgCData(uint32_t* oldp, CData newval, int bits) { const uint32_t diff = *oldp ^ newval; if (VL_UNLIKELY(diff)) fullCData(oldp, newval, bits); } - VL_ATTR_ALWINLINE inline void chgSData(uint32_t* oldp, SData newval, int bits) { + VL_ATTR_ALWINLINE void chgSData(uint32_t* oldp, SData newval, int bits) { const uint32_t diff = *oldp ^ newval; if (VL_UNLIKELY(diff)) fullSData(oldp, newval, bits); } - VL_ATTR_ALWINLINE inline void chgIData(uint32_t* oldp, IData newval, int bits) { + VL_ATTR_ALWINLINE void chgIData(uint32_t* oldp, IData newval, int bits) { const uint32_t diff = *oldp ^ newval; if (VL_UNLIKELY(diff)) fullIData(oldp, newval, bits); } - VL_ATTR_ALWINLINE inline void chgQData(uint32_t* oldp, QData newval, int bits) { + VL_ATTR_ALWINLINE void chgQData(uint32_t* oldp, QData newval, int bits) { const uint64_t diff = *reinterpret_cast(oldp) ^ newval; if (VL_UNLIKELY(diff)) fullQData(oldp, newval, bits); } - VL_ATTR_ALWINLINE inline void chgWData(uint32_t* oldp, const WData* newvalp, int bits) { + VL_ATTR_ALWINLINE void chgWData(uint32_t* oldp, const WData* newvalp, int bits) { for (int i = 0; i < (bits + 31) / 32; ++i) { if (VL_UNLIKELY(oldp[i] ^ newvalp[i])) { fullWData(oldp, newvalp, bits); @@ -469,7 +469,7 @@ public: } } } - VL_ATTR_ALWINLINE inline void chgDouble(uint32_t* oldp, double newval) { + VL_ATTR_ALWINLINE void chgDouble(uint32_t* oldp, double newval) { // cppcheck-suppress invalidPointerCast if (VL_UNLIKELY(*reinterpret_cast(oldp) != newval)) fullDouble(oldp, newval); } @@ -498,48 +498,48 @@ public: // Hot path internal interface to Verilator generated code // Offloaded tracing. Just dump everything in the offload buffer - inline void chgBit(uint32_t code, CData newval) { + void chgBit(uint32_t code, CData newval) { m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_BIT_0 | newval; m_offloadBufferWritep[1] = code; m_offloadBufferWritep += 2; VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp);); } - inline void chgCData(uint32_t code, CData newval, int bits) { + void chgCData(uint32_t code, CData newval, int bits) { m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_CDATA; m_offloadBufferWritep[1] = code; m_offloadBufferWritep[2] = newval; m_offloadBufferWritep += 3; VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp);); } - inline void chgSData(uint32_t code, SData newval, int bits) { + void chgSData(uint32_t code, SData newval, int bits) { m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_SDATA; m_offloadBufferWritep[1] = code; m_offloadBufferWritep[2] = newval; m_offloadBufferWritep += 3; VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp);); } - inline void chgIData(uint32_t code, IData newval, int bits) { + void chgIData(uint32_t code, IData newval, int bits) { m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_IDATA; m_offloadBufferWritep[1] = code; m_offloadBufferWritep[2] = newval; m_offloadBufferWritep += 3; VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp);); } - inline void chgQData(uint32_t code, QData newval, int bits) { + void chgQData(uint32_t code, QData newval, int bits) { m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_QDATA; m_offloadBufferWritep[1] = code; *reinterpret_cast(m_offloadBufferWritep + 2) = newval; m_offloadBufferWritep += 4; VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp);); } - inline void chgWData(uint32_t code, const WData* newvalp, int bits) { + void chgWData(uint32_t code, const WData* newvalp, int bits) { m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_WDATA; m_offloadBufferWritep[1] = code; m_offloadBufferWritep += 2; for (int i = 0; i < (bits + 31) / 32; ++i) { *m_offloadBufferWritep++ = newvalp[i]; } VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp);); } - inline void chgDouble(uint32_t code, double newval) { + void chgDouble(uint32_t code, double newval) { m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_DOUBLE; m_offloadBufferWritep[1] = code; // cppcheck-suppress invalidPointerCast diff --git a/include/verilated_trace_imp.h b/include/verilated_trace_imp.h index 0663986f1..90dcc2e70 100644 --- a/include/verilated_trace_imp.h +++ b/include/verilated_trace_imp.h @@ -551,15 +551,15 @@ template <> void VerilatedTrace::runOffloadedCallbacks( const std::vector& cbVec) { // Fall back on sequential execution - for (const CallbackRecord& cbr : cbVec) { #ifdef VL_THREADED + for (const CallbackRecord& cbr : cbVec) { Buffer* traceBufferp = getTraceBuffer(); cbr.m_dumpOffloadCb(cbr.m_userp, static_cast(traceBufferp)); commitTraceBuffer(traceBufferp); -#else - VL_FATAL_MT(__FILE__, __LINE__, "", "Unreachable"); -#endif } +#else + if (!cbVec.empty()) VL_FATAL_MT(__FILE__, __LINE__, "", "Unreachable"); +#endif } template <> @@ -586,7 +586,9 @@ void VerilatedTrace::dump(uint64_t timeui) VL_MT_SAFE_EXCLUD if (!preChangeDump()) return; } +#ifdef VL_THREADED uint32_t* bufferp = nullptr; +#endif if (offload()) { #ifdef VL_THREADED // Currently only incremental dumps run on the worker thread diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index ed36e6583..2d0cc57f0 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -632,10 +632,10 @@ void VerilatedVcd::commitTraceBuffer(VerilatedVcd::Buffer* bufp) { //============================================================================= // Trace rendering primitives -static inline void -VerilatedVcdCCopyAndAppendNewLine(char* writep, const char* suffixp) VL_ATTR_NO_SANITIZE_ALIGN; +static void VerilatedVcdCCopyAndAppendNewLine(char* writep, + const char* suffixp) VL_ATTR_NO_SANITIZE_ALIGN; -static inline void VerilatedVcdCCopyAndAppendNewLine(char* writep, const char* suffixp) { +static void VerilatedVcdCCopyAndAppendNewLine(char* writep, const char* suffixp) { // Copy the whole suffix (this avoid having hard to predict branches which // helps a lot). Note: The maximum length of the suffix is // VL_TRACE_MAX_VCD_CODE_SIZE + 2 == 7, but we unroll this here for speed. diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index 9079ef926..2967225b1 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -73,7 +73,7 @@ private: void bufferResize(size_t minsize); void bufferFlush() VL_MT_UNSAFE_ONE; - inline void bufferCheck() { + void bufferCheck() { // Flush the write buffer if there's not enough space left for new information // We only call this once per vector, so we need enough slop for a very wide "b###" line if (VL_UNLIKELY(m_writep > m_wrFlushp)) bufferFlush(); @@ -210,13 +210,13 @@ class VerilatedVcdBuffer VL_NOT_FINAL { // Implementation of VerilatedTraceBuffer interface // Implementations of duck-typed methods for VerilatedTraceBuffer. These are // called from only one place (the full* methods), so always inline them. - VL_ATTR_ALWINLINE inline void emitBit(uint32_t code, CData newval); - VL_ATTR_ALWINLINE inline void emitCData(uint32_t code, CData newval, int bits); - VL_ATTR_ALWINLINE inline void emitSData(uint32_t code, SData newval, int bits); - VL_ATTR_ALWINLINE inline void emitIData(uint32_t code, IData newval, int bits); - VL_ATTR_ALWINLINE inline void emitQData(uint32_t code, QData newval, int bits); - VL_ATTR_ALWINLINE inline void emitWData(uint32_t code, const WData* newvalp, int bits); - VL_ATTR_ALWINLINE inline void emitDouble(uint32_t code, double newval); + VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval); + VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits); + VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits); + VL_ATTR_ALWINLINE void emitIData(uint32_t code, IData newval, int bits); + VL_ATTR_ALWINLINE void emitQData(uint32_t code, QData newval, int bits); + VL_ATTR_ALWINLINE void emitWData(uint32_t code, const WData* newvalp, int bits); + VL_ATTR_ALWINLINE void emitDouble(uint32_t code, double newval); }; //============================================================================= @@ -313,7 +313,7 @@ public: } // Internal class access - inline VerilatedVcd* spTrace() { return &m_sptrace; } + VerilatedVcd* spTrace() { return &m_sptrace; } }; #endif // guard diff --git a/include/verilated_vcd_sc.h b/include/verilated_vcd_sc.h index a32134b23..c0ba6e528 100644 --- a/include/verilated_vcd_sc.h +++ b/include/verilated_vcd_sc.h @@ -55,35 +55,34 @@ public: spTrace()->set_time_resolution(sc_get_time_resolution().to_string()); } /// Destruct, flush, and close the dump - virtual ~VerilatedVcdSc() /*override*/ { close(); } + ~VerilatedVcdSc() override { close(); } // METHODS - for SC kernel // Called by SystemC simulate() - virtual void cycle(bool delta_cycle) { + void cycle(bool delta_cycle) override { if (!delta_cycle) this->dump(sc_time_stamp().to_double()); } // Override VerilatedVcdC. Must be called after starting simulation. - // cppcheck-suppress missingOverride // GCC won't accept override - virtual void open(const char* filename) /*override*/ VL_MT_SAFE; + void open(const char* filename) override VL_MT_SAFE; private: // METHODS - Fake outs for linker #ifdef NC_SYSTEMC // Cadence Incisive has these as abstract functions so we must create them - virtual void set_time_unit(int exponent10_seconds) {} // deprecated + void set_time_unit(int exponent10_seconds) override {} // deprecated #endif - virtual void set_time_unit(double v, sc_time_unit tu) {} // LCOV_EXCL_LINE + void set_time_unit(double v, sc_time_unit tu) override {} // LCOV_EXCL_LINE //-------------------------------------------------- // SystemC 2.1.v1 -#define DECL_TRACE_METHOD_A(tp) virtual void trace(const tp& object, const std::string& name); +#define DECL_TRACE_METHOD_A(tp) void trace(const tp& object, const std::string& name) override; #define DECL_TRACE_METHOD_B(tp) \ - virtual void trace(const tp& object, const std::string& name, int width); + void trace(const tp& object, const std::string& name, int width) override; - virtual void write_comment(const std::string&); - virtual void trace(const unsigned int&, const std::string&, const char**); + void write_comment(const std::string&) override; + void trace(const unsigned int&, const std::string&, const char**) override; // clang-format off // Formatting matches that of sc_trace.h diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index ff2d25c27..56f7d5e42 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -96,7 +96,7 @@ public: *(reinterpret_cast(newp)) = activeMagic(); return newp + 8; } - static void operator delete(void* obj, size_t /*size*/)VL_MT_SAFE { + static void operator delete(void* obj, size_t /*size*/) VL_MT_SAFE { uint8_t* const oldp = (static_cast(obj)) - 8; if (VL_UNLIKELY(*(reinterpret_cast(oldp)) != activeMagic())) { VL_FATAL_MT(__FILE__, __LINE__, "", @@ -114,7 +114,7 @@ public: static VerilatedVpio* castp(vpiHandle h) { return dynamic_cast(reinterpret_cast(h)); } - inline vpiHandle castVpiHandle() { return reinterpret_cast(this); } + vpiHandle castVpiHandle() { return reinterpret_cast(this); } // ACCESSORS virtual const char* name() const { return ""; } virtual const char* fullname() const { return ""; } diff --git a/include/verilatedos.h b/include/verilatedos.h index 12763f815..c5677b992 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -39,7 +39,7 @@ #ifdef __GNUC__ # define VL_ATTR_ALIGNED(alignment) __attribute__((aligned(alignment))) -# define VL_ATTR_ALWINLINE __attribute__((always_inline)) +# define VL_ATTR_ALWINLINE __attribute__((always_inline)) inline # define VL_ATTR_NOINLINE __attribute__((noinline)) # define VL_ATTR_COLD __attribute__((cold)) # define VL_ATTR_HOT __attribute__((hot)) @@ -548,8 +548,8 @@ struct reverse_wrapper { explicit reverse_wrapper(const T& a_v) : m_v(a_v) {} - inline auto begin() -> decltype(m_v.rbegin()) { return m_v.rbegin(); } - inline auto end() -> decltype(m_v.rend()) { return m_v.rend(); } + auto begin() -> decltype(m_v.rbegin()) { return m_v.rbegin(); } + auto end() -> decltype(m_v.rend()) { return m_v.rend(); } }; // C++20's std::ranges::reverse_view @@ -563,6 +563,7 @@ template T const& as_const(T& v) { return v; } + }; // namespace vlstd //========================================================================= diff --git a/nodist/code_coverage.dat b/nodist/code_coverage.dat index bff045d22..5197f226f 100644 --- a/nodist/code_coverage.dat +++ b/nodist/code_coverage.dat @@ -48,6 +48,7 @@ exclude_line_regexp(r'\bNUM_ASSERT') exclude_line_regexp(r'\bERROR_RSVD_WORD') exclude_line_regexp(r'\bV3ERROR_NA') exclude_line_regexp(r'\bUINFO\b') +exclude_line_regexp(r'\bVL_DEFINE_DEBUG_FUNCTIONS\b') # Exclude for branch coverage only exclude_branch_regexp(r'\bdebug\(\)') diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 140be6086..346521767 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -79,7 +79,7 @@ ifeq ($(VL_NOOPT),1) CPPFLAGS += -O0 else ifeq ($(VL_DEBUG),) # Optimize -CPPFLAGS += -O2 +CPPFLAGS += -O3 else # Debug CPPFLAGS += @CFG_CXXFLAGS_DEBUG@ -DVL_DEBUG -D_GLIBCXX_DEBUG @@ -276,9 +276,16 @@ VLCOV_OBJS = \ NON_STANDALONE_HEADERS = \ V3AstInlines.h \ - V3AstNodes.h \ + V3AstNodeDType.h \ + V3AstNodeMath.h \ + V3AstNodeOther.h \ V3WidthCommit.h \ +AST_DEFS := \ + V3AstNodeDType.h \ + V3AstNodeMath.h \ + V3AstNodeOther.h \ + #### Linking ifeq ($(VL_VLCOV),) @@ -301,8 +308,8 @@ V3Number_test: V3Number_test.o #### Modules -%__gen.cpp: %.cpp $(ASTGEN) V3Ast.h V3AstNodes.h - $(PYTHON3) $(ASTGEN) -I $(srcdir) $*.cpp +%__gen.cpp: %.cpp $(ASTGEN) $(AST_DEFS) + $(PYTHON3) $(ASTGEN) -I $(srcdir) $(foreach f,$(AST_DEFS),--astdef $f) $*.cpp %.o: %.cpp $(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@ @@ -332,8 +339,8 @@ vlcovgen.d: $(VLCOVGEN) $(srcdir)/../include/verilated_cov_key.h $(PYTHON3) $(VLCOVGEN) --srcdir $(srcdir) touch $@ -V3Ast__gen_classes.h : $(ASTGEN) V3Ast.h V3AstNodes.h - $(PYTHON3) $(ASTGEN) -I $(srcdir) --classes +V3Ast__gen_classes.h : $(ASTGEN) $(AST_DEFS) + $(PYTHON3) $(ASTGEN) -I $(srcdir) $(foreach f,$(AST_DEFS),--astdef $f) --classes V3ParseBison.h: V3ParseBison.c diff --git a/src/V3Active.cpp b/src/V3Active.cpp index fa629c11f..ac8080eb1 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -38,6 +38,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //***** See below for main transformation engine //###################################################################### @@ -66,8 +68,8 @@ public: : V3GraphVertex{graphp} , m_name{name} , m_type{type} {} - virtual string name() const override { return m_name + " " + typestr(); } - virtual string dotColor() const override { return user() ? "green" : "black"; } + string name() const override { return m_name + " " + typestr(); } + string dotColor() const override { return user() ? "green" : "black"; } virtual int type() const { return m_type; } }; @@ -79,8 +81,6 @@ protected: LatchDetectGraphVertex* m_curVertexp = nullptr; // Current latch detection graph vertex std::vector m_outputs; // Vector of lvalues encountered on this pass - VL_DEBUG_FUNC; // Declare debug() - static LatchDetectGraphVertex* castVertexp(void* vertexp) { return reinterpret_cast(vertexp); } @@ -120,7 +120,7 @@ protected: public: LatchDetectGraph() { clear(); } - virtual ~LatchDetectGraph() override { clear(); } + ~LatchDetectGraph() override { clear(); } // ACCESSORS LatchDetectGraphVertex* currentp() { return m_curVertexp; } void currentp(LatchDetectGraphVertex* vertex) { m_curVertexp = vertex; } @@ -183,7 +183,7 @@ public: << " (not all control paths of combinational always assign a value)\n" << nodep->warnMore() << "... Suggest use of always_latch for intentional latches"); - if (debug() >= 9) dumpDotFilePrefixed("latch_" + vrp->name()); + if (dumpGraph() >= 9) dumpDotFilePrefixed("latch_" + vrp->name()); } vertp->user(false); // Clear again (see above) vrp->varp()->isLatched(latch_detected); @@ -198,12 +198,7 @@ public: //###################################################################### // Collect existing active names -class ActiveBaseVisitor VL_NOT_FINAL : public VNVisitor { -protected: - VL_DEBUG_FUNC; // Declare debug() -}; - -class ActiveNamer final : public ActiveBaseVisitor { +class ActiveNamer final : public VNVisitor { private: // STATE AstScope* m_scopep = nullptr; // Current scope to add statement to @@ -216,10 +211,10 @@ private: // METHODS void addActive(AstActive* nodep) { UASSERT_OBJ(m_scopep, nodep, "nullptr scope"); - m_scopep->addActivep(nodep); + m_scopep->addBlocksp(nodep); } // VISITORS - virtual void visit(AstScope* nodep) override { + void visit(AstScope* nodep) override { m_scopep = nodep; m_iActivep = nullptr; m_cActivep = nullptr; @@ -227,13 +222,13 @@ private: iterateChildren(nodep); // Don't clear scopep, the namer persists beyond this visit } - virtual void visit(AstSenTree* nodep) override { + void visit(AstSenTree* nodep) override { // Simplify sensitivity list VL_DO_DANGLING(V3Const::constifyExpensiveEdit(nodep), nodep); } //-------------------- - virtual void visit(AstNodeStmt*) override {} // Accelerate - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNodeStmt*) override {} // Accelerate + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // METHODS @@ -275,14 +270,14 @@ public: // CONSTRUCTORS ActiveNamer() = default; - virtual ~ActiveNamer() override = default; + ~ActiveNamer() override = default; void main(AstScope* nodep) { iterate(nodep); } }; //###################################################################### // Latch checking visitor -class ActiveLatchCheckVisitor final : public ActiveBaseVisitor { +class ActiveLatchCheckVisitor final : public VNVisitor { private: // NODE STATE // Input: @@ -291,25 +286,25 @@ private: // STATE LatchDetectGraph m_graph; // Graph used to detect latches in combo always // VISITORS - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { const AstVar* const varp = nodep->varp(); if (nodep->access().isWriteOrRW() && varp->isSignal() && !varp->isUsedLoopIdx()) { m_graph.addAssignment(nodep); } } - virtual void visit(AstNodeIf* nodep) override { + void visit(AstNodeIf* nodep) override { if (!nodep->isBoundsCheck()) { LatchDetectGraphVertex* const parentp = m_graph.currentp(); LatchDetectGraphVertex* const branchp = m_graph.addPathVertex(parentp, "BRANCH", true); m_graph.addPathVertex(branchp, "IF"); - iterateAndNextNull(nodep->ifsp()); + iterateAndNextNull(nodep->thensp()); m_graph.addPathVertex(branchp, "ELSE"); iterateAndNextNull(nodep->elsesp()); m_graph.currentp(parentp); } } //-------------------- - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -324,7 +319,7 @@ public: //###################################################################### // Replace unsupported non-blocking assignments with blocking assignments -class ActiveDlyVisitor final : public ActiveBaseVisitor { +class ActiveDlyVisitor final : public VNVisitor { public: enum CheckType : uint8_t { CT_SEQ, CT_COMB, CT_INITIAL }; @@ -333,7 +328,7 @@ private: const CheckType m_check; // Process type we are checking // VISITORS - virtual void visit(AstAssignDly* nodep) override { + void visit(AstAssignDly* nodep) override { // Non-blocking assignments are OK in sequential processes if (m_check == CT_SEQ) return; @@ -357,7 +352,7 @@ private: VL_DO_DANGLING(nodep->deleteTree(), nodep); } - virtual void visit(AstAssign* nodep) override { + void visit(AstAssign* nodep) override { // Blocking assignments are always OK in combinational (and initial/final) processes if (m_check != CT_SEQ) return; @@ -380,7 +375,7 @@ private: } //-------------------- - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -394,7 +389,7 @@ public: //###################################################################### // Active class functions -class ActiveVisitor final : public ActiveBaseVisitor { +class ActiveVisitor final : public VNVisitor { private: // NODE STATE // Each call to V3Const::constify @@ -407,7 +402,7 @@ private: bool m_itemSequent = false; // Found a SenItem sequential // VISITORS - virtual void visit(AstScope* nodep) override { + void visit(AstScope* nodep) override { // Create required actives and add to scope UINFO(4, " SCOPE " << nodep << endl); // Clear last scope's names, and collect this scope's existing names @@ -415,10 +410,10 @@ private: m_scopeFinalp = nullptr; iterateChildren(nodep); } - virtual void visit(AstActive* nodep) override { + void visit(AstActive* nodep) override { // Actives are being formed, so we can ignore any already made } - virtual void visit(AstInitialStatic* nodep) override { + void visit(AstInitialStatic* nodep) override { // Relink to IACTIVE, unless already under it UINFO(4, " INITIAL " << nodep << endl); const ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL}; @@ -426,7 +421,7 @@ private: nodep->unlinkFrBack(); wantactivep->addStmtsp(nodep); } - virtual void visit(AstInitial* nodep) override { + void visit(AstInitial* nodep) override { // Relink to IACTIVE, unless already under it UINFO(4, " INITIAL " << nodep << endl); const ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL}; @@ -434,31 +429,31 @@ private: nodep->unlinkFrBack(); wantactivep->addStmtsp(nodep); } - virtual void visit(AstAssignAlias* nodep) override { + void visit(AstAssignAlias* nodep) override { // Relink to CACTIVE, unless already under it UINFO(4, " ASSIGNW " << nodep << endl); AstActive* const wantactivep = m_namer.getCActive(nodep->fileline()); nodep->unlinkFrBack(); wantactivep->addStmtsp(nodep); } - virtual void visit(AstAssignW* nodep) override { + void visit(AstAssignW* nodep) override { // Relink to CACTIVE, unless already under it UINFO(4, " ASSIGNW " << nodep << endl); AstActive* const wantactivep = m_namer.getCActive(nodep->fileline()); nodep->unlinkFrBack(); wantactivep->addStmtsp(nodep); } - virtual void visit(AstCoverToggle* nodep) override { + void visit(AstCoverToggle* nodep) override { // Relink to CACTIVE, unless already under it UINFO(4, " COVERTOGGLE " << nodep << endl); AstActive* const wantactivep = m_namer.getCActive(nodep->fileline()); nodep->unlinkFrBack(); wantactivep->addStmtsp(nodep); } - virtual void visit(AstFinal* nodep) override { + void visit(AstFinal* nodep) override { // Relink to CFUNC for the final UINFO(4, " FINAL " << nodep << endl); - if (!nodep->bodysp()) { // Empty, Kill it. + if (!nodep->stmtsp()) { // Empty, Kill it. VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); return; } @@ -471,10 +466,10 @@ private: m_scopeFinalp->isStatic(false); m_scopeFinalp->isLoose(true); m_scopeFinalp->slow(true); - m_namer.scopep()->addActivep(m_scopeFinalp); + m_namer.scopep()->addBlocksp(m_scopeFinalp); } nodep->unlinkFrBack(); - m_scopeFinalp->addStmtsp(nodep->bodysp()->unlinkFrBackWithNext()); + m_scopeFinalp->addStmtsp(nodep->stmtsp()->unlinkFrBackWithNext()); VL_DO_DANGLING(nodep->deleteTree(), nodep); } @@ -537,33 +532,33 @@ private: ActiveDlyVisitor{nodep, ActiveDlyVisitor::CT_SEQ}; } } - virtual void visit(AstAlways* nodep) override { + void visit(AstAlways* nodep) override { // Move always to appropriate ACTIVE based on its sense list UINFO(4, " ALW " << nodep << endl); // if (debug() >= 9) nodep->dumpTree(cout, " Alw: "); - if (!nodep->bodysp()) { + if (!nodep->stmtsp()) { // Empty always. Kill it. VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); return; } visitAlways(nodep, nodep->sensesp(), nodep->keyword()); } - virtual void visit(AstAlwaysPostponed* nodep) override { + void visit(AstAlwaysPostponed* nodep) override { UINFO(4, " ALW " << nodep << endl); - if (!nodep->bodysp()) { + if (!nodep->stmtsp()) { VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); return; } visitAlways(nodep, nullptr, VAlwaysKwd::ALWAYS); } - virtual void visit(AstAlwaysPublic* nodep) override { + void visit(AstAlwaysPublic* nodep) override { // Move always to appropriate ACTIVE based on its sense list UINFO(4, " ALWPub " << nodep << endl); // if (debug() >= 9) nodep->dumpTree(cout, " Alw: "); visitAlways(nodep, nodep->sensesp(), VAlwaysKwd::ALWAYS); } - virtual void visit(AstSenItem* nodep) override { + void visit(AstSenItem* nodep) override { if (nodep->varrefp()) { if (const AstBasicDType* const basicp = nodep->varrefp()->dtypep()->basicp()) { if (basicp->isEventValue()) { @@ -592,9 +587,9 @@ private: } //-------------------- - virtual void visit(AstNodeMath*) override {} // Accelerate - virtual void visit(AstVarScope*) override {} // Accelerate - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNodeMath*) override {} // Accelerate + void visit(AstVarScope*) override {} // Accelerate + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -608,5 +603,5 @@ public: void V3Active::activeAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { ActiveVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("active", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("active", 0, dumpTree() >= 3); } diff --git a/src/V3ActiveTop.cpp b/src/V3ActiveTop.cpp index e39742dbd..eefa36685 100644 --- a/src/V3ActiveTop.cpp +++ b/src/V3ActiveTop.cpp @@ -33,6 +33,8 @@ #include "V3Global.h" #include "V3SenTree.h" +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Active class functions @@ -49,16 +51,15 @@ private: SenTreeFinder m_finder; // Find global sentree's / add them under the AstTopScope // METHODS - VL_DEBUG_FUNC; // Declare debug() // VISITORS - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { // Create required actives and add to module // We can start ordering at a module, or a scope UINFO(4, " MOD " << nodep << endl); iterateChildren(nodep); } - virtual void visit(AstActive* nodep) override { + void visit(AstActive* nodep) override { UINFO(4, " ACTIVE " << nodep << endl); // Remove duplicate clocks and such; sensesp() may change! V3Const::constifyExpensiveEdit(nodep); @@ -101,27 +102,27 @@ private: // No need to do statements under it, they're already moved. // iterateChildren(nodep); } - virtual void visit(AstNodeProcedure* nodep) override { // LCOV_EXCL_LINE + void visit(AstNodeProcedure* nodep) override { // LCOV_EXCL_LINE nodep->v3fatalSrc("Node should have been under ACTIVE"); } - virtual void visit(AstAssignAlias* nodep) override { // LCOV_EXCL_LINE + void visit(AstAssignAlias* nodep) override { // LCOV_EXCL_LINE nodep->v3fatalSrc("Node should have been under ACTIVE"); } - virtual void visit(AstAssignW* nodep) override { // LCOV_EXCL_LINE + void visit(AstAssignW* nodep) override { // LCOV_EXCL_LINE nodep->v3fatalSrc("Node should have been under ACTIVE"); } - virtual void visit(AstAlwaysPublic* nodep) override { // LCOV_EXCL_LINE + void visit(AstAlwaysPublic* nodep) override { // LCOV_EXCL_LINE nodep->v3fatalSrc("Node should have been under ACTIVE"); } //-------------------- - virtual void visit(AstNodeMath*) override {} // Accelerate - virtual void visit(AstVarScope*) override {} // Accelerate - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNodeMath*) override {} // Accelerate + void visit(AstVarScope*) override {} // Accelerate + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit ActiveTopVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~ActiveTopVisitor() override = default; + ~ActiveTopVisitor() override = default; }; //###################################################################### @@ -130,5 +131,5 @@ public: void V3ActiveTop::activeTopAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { ActiveTopVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("activetop", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("activetop", 0, dumpTree() >= 3); } diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 86e8710a8..c15cd269d 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -23,6 +23,8 @@ #include "V3Global.h" #include "V3Stats.h" +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Assert class functions @@ -70,7 +72,7 @@ private: if (!m_monitorNumVarp) { m_monitorNumVarp = new AstVar{nodep->fileline(), VVarType::MODULETEMP, "__VmonitorNum", nodep->findUInt64DType()}; - v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(m_monitorNumVarp); + v3Global.rootp()->dollarUnitPkgAddp()->addStmtsp(m_monitorNumVarp); } const auto varrefp = new AstVarRef(nodep->fileline(), m_monitorNumVarp, access); varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp()); @@ -80,7 +82,7 @@ private: if (!m_monitorOffVarp) { m_monitorOffVarp = new AstVar{nodep->fileline(), VVarType::MODULETEMP, "__VmonitorOff", nodep->findBitDType()}; - v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(m_monitorOffVarp); + v3Global.rootp()->dollarUnitPkgAddp()->addStmtsp(m_monitorOffVarp); } const auto varrefp = new AstVarRef(nodep->fileline(), m_monitorOffVarp, access); varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp()); @@ -147,7 +149,7 @@ private: selfDestruct = true; } else { // V3Coverage assigned us a bucket to increment. - AstCoverInc* const covincp = VN_AS(snodep->coverincp(), CoverInc); + AstCoverInc* const covincp = VN_AS(snodep->coverincsp(), CoverInc); UASSERT_OBJ(covincp, snodep, "Missing AstCoverInc under assertion"); covincp->unlinkFrBackWithNext(); // next() might have AstAssign for trace if (message != "") covincp->declp()->comment(message); @@ -196,7 +198,7 @@ private: } // VISITORS - virtual void visit(AstIf* nodep) override { + void visit(AstIf* nodep) override { if (nodep->user1SetOnce()) return; if (nodep->uniquePragma() || nodep->unique0Pragma()) { const AstNodeIf* ifp = nodep; @@ -209,7 +211,7 @@ private: iterateAndNextNull(ifp->condp()); // Recurse into the true case. - iterateAndNextNull(ifp->ifsp()); + iterateAndNextNull(ifp->thensp()); // If the last else is not an else if, recurse into that too. if (ifp->elsesp() && !nextifp) { // @@ -254,7 +256,7 @@ private: } //========== Case assertions - virtual void visit(AstCase* nodep) override { + void visit(AstCase* nodep) override { iterateChildren(nodep); if (!nodep->user1SetOnce()) { bool has_default = false; @@ -323,7 +325,7 @@ private: } //========== Past - virtual void visit(AstPast* nodep) override { + void visit(AstPast* nodep) override { iterateChildren(nodep); uint32_t ticks = 1; if (nodep->ticksp()) { @@ -338,28 +340,28 @@ private: sentreep->unlinkFrBack(); AstAlways* const alwaysp = new AstAlways(nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, nullptr); - m_modp->addStmtp(alwaysp); + m_modp->addStmtsp(alwaysp); for (uint32_t i = 0; i < ticks; ++i) { AstVar* const outvarp = new AstVar( nodep->fileline(), VVarType::MODULETEMP, "_Vpast_" + cvtToStr(m_modPastNum++) + "_" + cvtToStr(i), inp->dtypep()); - m_modp->addStmtp(outvarp); + m_modp->addStmtsp(outvarp); AstNode* const assp = new AstAssignDly( nodep->fileline(), new AstVarRef(nodep->fileline(), outvarp, VAccess::WRITE), inp); - alwaysp->addStmtp(assp); + alwaysp->addStmtsp(assp); // if (debug() >= 9) assp->dumpTree(cout, "-ass: "); invarp = outvarp; inp = new AstVarRef(nodep->fileline(), invarp, VAccess::READ); } nodep->replaceWith(inp); } - virtual void visit(AstSampled* nodep) override { + void visit(AstSampled* nodep) override { nodep->replaceWith(nodep->exprp()->unlinkFrBack()); VL_DO_DANGLING(pushDeletep(nodep), nodep); } //========== Statements - virtual void visit(AstDisplay* nodep) override { + void visit(AstDisplay* nodep) override { iterateChildren(nodep); // Replace the special types with standard text if (nodep->displayType() == VDisplayType::DT_INFO) { @@ -387,7 +389,7 @@ private: stmtsp}; ifp->branchPred(VBranchPred::BP_UNLIKELY); AstNode* const newp = new AstAlwaysPostponed{fl, ifp}; - m_modp->addStmtp(newp); + m_modp->addStmtsp(newp); } else if (nodep->displayType() == VDisplayType::DT_STROBE) { nodep->displayType(VDisplayType::DT_DISPLAY); // Need one-shot @@ -395,7 +397,7 @@ private: const auto varp = new AstVar{fl, VVarType::MODULETEMP, "__Vstrobe" + cvtToStr(m_modStrobeNum++), nodep->findBitDType()}; - m_modp->addStmtp(varp); + m_modp->addStmtsp(varp); // Where $strobe was we do "__Vstrobe = '1;" const auto newsetp = new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, new AstConst{fl, AstConst::BitTrue{}}}; @@ -407,35 +409,35 @@ private: AstNode* const newp = new AstAlwaysPostponed{fl, ifp}; stmtsp->addNext(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, new AstConst{fl, AstConst::BitFalse{}}}); - m_modp->addStmtp(newp); + m_modp->addStmtsp(newp); } } - virtual void visit(AstMonitorOff* nodep) override { + void visit(AstMonitorOff* nodep) override { const auto newp = new AstAssign(nodep->fileline(), newMonitorOffVarRefp(nodep, VAccess::WRITE), new AstConst(nodep->fileline(), AstConst::BitTrue{}, nodep->off())); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } - virtual void visit(AstAssert* nodep) override { + void visit(AstAssert* nodep) override { iterateChildren(nodep); newPslAssertion(nodep, nodep->failsp()); } - virtual void visit(AstAssertIntrinsic* nodep) override { + void visit(AstAssertIntrinsic* nodep) override { iterateChildren(nodep); newPslAssertion(nodep, nodep->failsp()); } - virtual void visit(AstCover* nodep) override { + void visit(AstCover* nodep) override { iterateChildren(nodep); newPslAssertion(nodep, nullptr); } - virtual void visit(AstRestrict* nodep) override { + void visit(AstRestrict* nodep) override { iterateChildren(nodep); // IEEE says simulator ignores these VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { VL_RESTORER(m_modp); VL_RESTORER(m_modPastNum); VL_RESTORER(m_modStrobeNum); @@ -446,7 +448,7 @@ private: iterateChildren(nodep); } } - virtual void visit(AstBegin* nodep) override { + void visit(AstBegin* nodep) override { // This code is needed rather than a visitor in V3Begin, // because V3Assert is called before V3Begin VL_RESTORER(m_beginp); @@ -456,12 +458,12 @@ private: } } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit AssertVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~AssertVisitor() override { + ~AssertVisitor() override { V3Stats::addStat("Assertions, assert non-immediate statements", m_statAsNotImm); V3Stats::addStat("Assertions, assert immediate statements", m_statAsImm); V3Stats::addStat("Assertions, cover statements", m_statCover); @@ -475,5 +477,5 @@ public: void V3Assert::assertAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { AssertVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("assert", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("assert", 0, dumpTree() >= 3); } diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp index 705dfcbb2..bb0ae8b27 100644 --- a/src/V3AssertPre.cpp +++ b/src/V3AssertPre.cpp @@ -25,6 +25,8 @@ #include "V3Ast.h" #include "V3Global.h" +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Assert class functions @@ -45,7 +47,6 @@ private: AstNode* m_disablep = nullptr; // Last disable // METHODS - VL_DEBUG_FUNC; // Declare debug() AstSenTree* newSenTree(AstNode* nodep) { // Create sentree based on clocked or default clock @@ -69,7 +70,7 @@ private: // VISITORS //========== Statements - virtual void visit(AstClocking* nodep) override { + void visit(AstClocking* nodep) override { UINFO(8, " CLOCKING" << nodep << endl); // Store the new default clock, reset on new module m_seniDefaultp = nodep->sensesp(); @@ -81,14 +82,14 @@ private: } VL_DO_DANGLING(pushDeletep(nodep), nodep); } - virtual void visit(AstAlways* nodep) override { + void visit(AstAlways* nodep) override { iterateAndNextNull(nodep->sensesp()); if (nodep->sensesp()) m_seniAlwaysp = nodep->sensesp()->sensesp(); - iterateAndNextNull(nodep->bodysp()); + iterateAndNextNull(nodep->stmtsp()); m_seniAlwaysp = nullptr; } - virtual void visit(AstNodeCoverOrAssert* nodep) override { + void visit(AstNodeCoverOrAssert* nodep) override { if (nodep->sentreep()) return; // Already processed clearAssertInfo(); // Find Clocking's buried under nodep->exprsp @@ -96,7 +97,7 @@ private: if (!nodep->immediate()) nodep->sentreep(newSenTree(nodep)); clearAssertInfo(); } - virtual void visit(AstFell* nodep) override { + void visit(AstFell* nodep) override { if (nodep->sentreep()) return; // Already processed iterateChildren(nodep); FileLine* const fl = nodep->fileline(); @@ -110,12 +111,12 @@ private: nodep->sentreep(newSenTree(nodep)); VL_DO_DANGLING(pushDeletep(nodep), nodep); } - virtual void visit(AstPast* nodep) override { + void visit(AstPast* nodep) override { if (nodep->sentreep()) return; // Already processed iterateChildren(nodep); nodep->sentreep(newSenTree(nodep)); } - virtual void visit(AstRose* nodep) override { + void visit(AstRose* nodep) override { if (nodep->sentreep()) return; // Already processed iterateChildren(nodep); FileLine* const fl = nodep->fileline(); @@ -129,7 +130,7 @@ private: nodep->sentreep(newSenTree(nodep)); VL_DO_DANGLING(pushDeletep(nodep), nodep); } - virtual void visit(AstStable* nodep) override { + void visit(AstStable* nodep) override { if (nodep->sentreep()) return; // Already processed iterateChildren(nodep); FileLine* const fl = nodep->fileline(); @@ -143,7 +144,7 @@ private: VL_DO_DANGLING(pushDeletep(nodep), nodep); } - virtual void visit(AstImplication* nodep) override { + void visit(AstImplication* nodep) override { if (nodep->sentreep()) return; // Already processed FileLine* const fl = nodep->fileline(); @@ -161,7 +162,7 @@ private: VL_DO_DANGLING(pushDeletep(nodep), nodep); } - virtual void visit(AstPropClocked* nodep) override { + void visit(AstPropClocked* nodep) override { // No need to iterate the body, once replace will get iterated iterateAndNextNull(nodep->sensesp()); if (m_senip) @@ -183,12 +184,12 @@ private: nodep->replaceWith(blockp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { iterateChildren(nodep); // Reset defaults m_seniDefaultp = nullptr; } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -197,7 +198,7 @@ public: // Process iterate(nodep); } - virtual ~AssertPreVisitor() override = default; + ~AssertPreVisitor() override = default; }; //###################################################################### @@ -206,5 +207,5 @@ public: void V3AssertPre::assertPreAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { AssertPreVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("assertpre", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("assertpre", 0, dumpTree() >= 3); } diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 213ddd3fb..8f7b102ef 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -28,6 +28,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //====================================================================== // Statics @@ -165,22 +167,22 @@ string AstNode::prettyName(const string& namein) { continue; } if (pos[0] == '_' && pos[1] == '_') { // Short-circuit - if (0 == strncmp(pos, "__BRA__", 7)) { + if (0 == std::strncmp(pos, "__BRA__", 7)) { pretty += "["; pos += 7; continue; } - if (0 == strncmp(pos, "__KET__", 7)) { + if (0 == std::strncmp(pos, "__KET__", 7)) { pretty += "]"; pos += 7; continue; } - if (0 == strncmp(pos, "__DOT__", 7)) { + if (0 == std::strncmp(pos, "__DOT__", 7)) { pretty += "."; pos += 7; continue; } - if (0 == strncmp(pos, "__PVT__", 7)) { + if (0 == std::strncmp(pos, "__PVT__", 7)) { pretty += ""; pos += 7; continue; @@ -212,8 +214,7 @@ string AstNode::prettyTypeName() const { //###################################################################### // Insertion -inline void AstNode::debugTreeChange(const AstNode* nodep, const char* prefix, int lineno, - bool next){ +void AstNode::debugTreeChange(const AstNode* nodep, const char* prefix, int lineno, bool next) { #ifdef VL_DEBUG // Called on all major tree changers. // Only for use for those really nasty bugs relating to internals @@ -234,7 +235,8 @@ inline void AstNode::debugTreeChange(const AstNode* nodep, const char* prefix, i #endif } -AstNode* AstNode::addNext(AstNode* nodep, AstNode* newp) { +template <> +AstNode* AstNode::addNext(AstNode* nodep, AstNode* newp) { // Add to m_nextp, returns this UDEBUGONLY(UASSERT_OBJ(newp, nodep, "Null item passed to addNext");); debugTreeChange(nodep, "-addNextThs: ", __LINE__, false); @@ -272,11 +274,6 @@ AstNode* AstNode::addNext(AstNode* nodep, AstNode* newp) { return nodep; } -AstNode* AstNode::addNextNull(AstNode* nodep, AstNode* newp) { - if (!newp) return nodep; - return addNext(nodep, newp); -} - void AstNode::addNextHere(AstNode* newp) { // Add to m_nextp on exact node passed, not at the end. // This could be at head, tail, or both (single) @@ -925,7 +922,7 @@ AstNode* AstNode::iterateSubtreeReturnEdits(VNVisitor& v) { } else if (!nodep->backp()) { // Calling on standalone tree; insert a shim node so we can keep // track, then delete it on completion - AstBegin* const tempp = new AstBegin(nodep->fileline(), "[EditWrapper]", nodep); + AstBegin* const tempp = new AstBegin{nodep->fileline(), "[EditWrapper]", nodep}; { VL_DO_DANGLING(tempp->stmtsp()->accept(v), nodep); // nodep to null as may be replaced @@ -1004,43 +1001,12 @@ bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ig //====================================================================== // Debugging -void AstNode::checkTreeIter(AstNode* backp) { +void AstNode::checkTreeIter(const AstNode* backp) const { // private: Check a tree and children UASSERT_OBJ(backp == this->backp(), this, "Back node inconsistent"); - if (VN_IS(this, NodeTermop) || VN_IS(this, NodeVarRef)) { - // Termops have a short-circuited iterateChildren, so check usage - UASSERT_OBJ(!(op1p() || op2p() || op3p() || op4p()), this, - "Terminal operation with non-terminals"); - } - if (m_op1p) m_op1p->checkTreeIterList(this); - if (m_op2p) m_op2p->checkTreeIterList(this); - if (m_op3p) m_op3p->checkTreeIterList(this); - if (m_op4p) m_op4p->checkTreeIterList(this); -} - -void AstNode::checkTreeIterList(AstNode* backp) { - // private: Check a (possible) list of nodes, this is always the head of the list - // Audited to make sure this is never nullptr - AstNode* const headp = this; - const AstNode* tailp = this; - for (AstNode* nodep = headp; nodep; nodep = nodep->nextp()) { - nodep->checkTreeIter(backp); - UASSERT_OBJ(headp == this || !nextp(), this, - "Headtailp should be null in middle of lists"); - tailp = nodep; - backp = nodep; - } - UASSERT_OBJ(headp->m_headtailp == tailp, headp, "Tail in headtailp is inconsistent"); - UASSERT_OBJ(tailp->m_headtailp == headp, tailp, "Head in headtailp is inconsistent"); -} - -void AstNode::checkTree() { - if (!debug()) return; - if (this->backp()) { - // Linked tree- check only the passed node - this->checkTreeIter(this->backp()); - } else { - this->checkTreeIterList(this->backp()); + switch (this->type()) { +#include "V3Ast__gen_op_checks.h" + default: VL_UNREACHABLE; // LCOV_EXCL_LINE } } @@ -1156,7 +1122,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump, boo if (logsp->fail()) v3fatal("Can't write " << filename); *logsp << "Verilator Tree Dump (format 0x3900) from to \n"; - if (editCountGbl() == editCountLast() && !(v3Global.opt.dumpTree() >= 9)) { + if (editCountGbl() == editCountLast() && ::dumpTree() < 9) { *logsp << '\n'; *logsp << "No changes since last dump!\n"; } else { @@ -1166,7 +1132,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump, boo } } if (doDump && v3Global.opt.debugEmitV()) V3EmitV::debugEmitV(filename + ".v"); - if (doCheck && (v3Global.opt.debugCheck() || v3Global.opt.dumpTree())) { + if (doCheck && (v3Global.opt.debugCheck() || ::dumpTree())) { // Error check checkTree(); // Broken isn't part of check tree because it can munge iterp's @@ -1217,7 +1183,11 @@ void AstNode::v3errorEnd(std::ostringstream& str) const { const_cast(this)->dump(nsstr); nsstr << endl; } - m_fileline->v3errorEnd(nsstr, instanceStr()); + // Don't look for instance name when warning is disabled. + // In case of large number of warnings, this can + // take significant amount of time + m_fileline->v3errorEnd(nsstr, + m_fileline->warnIsOff(V3Error::errorCode()) ? "" : instanceStr()); } } diff --git a/src/V3Ast.h b/src/V3Ast.h index b05c43318..01a6af34c 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -36,8 +36,6 @@ #include #include #include -// Things like: -// class V3AstNode; // Forward declarations class V3Graph; @@ -95,20 +93,20 @@ public: // const char* ascii() const {...}; enum en m_e; // cppcheck-suppress uninitVar // responsibility of each subclass - inline VNType() = default; + VNType() = default; // cppcheck-suppress noExplicitConstructor - inline VNType(en _e) + constexpr VNType(en _e) : m_e{_e} {} - explicit inline VNType(int _e) + explicit VNType(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } }; -inline bool operator==(const VNType& lhs, const VNType& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VNType& lhs, VNType::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VNType::en lhs, const VNType& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const VNType& lhs, const VNType& rhs) { return lhs.m_e == rhs.m_e; } +constexpr bool operator==(const VNType& lhs, VNType::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(VNType::en lhs, const VNType& rhs) { return lhs == rhs.m_e; } inline std::ostream& operator<<(std::ostream& os, const VNType& rhs) { return os << rhs.ascii(); } -//###################################################################### +// ###################################################################### class VLifetime final { public: @@ -118,26 +116,28 @@ public: static const char* const names[] = {"NONE", "VAUTOM", "VSTATIC"}; return names[m_e]; } - inline VLifetime() + VLifetime() : m_e{NONE} {} // cppcheck-suppress noExplicitConstructor - inline VLifetime(en _e) + constexpr VLifetime(en _e) : m_e{_e} {} - explicit inline VLifetime(int _e) + explicit VLifetime(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } bool isNone() const { return m_e == NONE; } bool isAutomatic() const { return m_e == AUTOMATIC; } bool isStatic() const { return m_e == STATIC; } }; -inline bool operator==(const VLifetime& lhs, const VLifetime& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VLifetime& lhs, VLifetime::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VLifetime::en lhs, const VLifetime& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const VLifetime& lhs, const VLifetime& rhs) { + return lhs.m_e == rhs.m_e; +} +constexpr bool operator==(const VLifetime& lhs, VLifetime::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(VLifetime::en lhs, const VLifetime& rhs) { return lhs == rhs.m_e; } inline std::ostream& operator<<(std::ostream& os, const VLifetime& rhs) { return os << rhs.ascii(); } -//###################################################################### +// ###################################################################### class VAccess final { public: @@ -159,16 +159,16 @@ public: static const char* const names[] = {"[RV] <-", "[LV] =>", "[LV] <=>", "--"}; return names[m_e]; } - inline VAccess() + VAccess() : m_e{READ} {} // cppcheck-suppress noExplicitConstructor - inline VAccess(en _e) + constexpr VAccess(en _e) : m_e{_e} {} - explicit inline VAccess(int _e) + explicit VAccess(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } VAccess invert() const { - return (m_e == READWRITE) ? VAccess(m_e) : (m_e == WRITE ? VAccess(READ) : VAccess(WRITE)); + return (m_e == READWRITE) ? VAccess{m_e} : (m_e == WRITE ? VAccess{READ} : VAccess{WRITE}); } bool isReadOnly() const { return m_e == READ; } // False with READWRITE bool isWriteOnly() const { return m_e == WRITE; } // False with READWRITE @@ -176,12 +176,12 @@ public: bool isWriteOrRW() const { return m_e == WRITE || m_e == READWRITE; } bool isRW() const { return m_e == READWRITE; } }; -inline bool operator==(const VAccess& lhs, const VAccess& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VAccess& lhs, VAccess::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VAccess::en lhs, const VAccess& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const VAccess& lhs, const VAccess& rhs) { return lhs.m_e == rhs.m_e; } +constexpr bool operator==(const VAccess& lhs, VAccess::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(VAccess::en lhs, const VAccess& rhs) { return lhs == rhs.m_e; } inline std::ostream& operator<<(std::ostream& os, const VAccess& rhs) { return os << rhs.ascii(); } -//###################################################################### +// ###################################################################### class VSigning final { public: @@ -196,29 +196,29 @@ public: static const char* const names[] = {"UNSIGNED", "SIGNED", "NOSIGN"}; return names[m_e]; } - inline VSigning() + VSigning() : m_e{UNSIGNED} {} // cppcheck-suppress noExplicitConstructor - inline VSigning(en _e) + constexpr VSigning(en _e) : m_e{_e} {} - static inline VSigning fromBool(bool isSigned) { // Factory method - return isSigned ? VSigning(SIGNED) : VSigning(UNSIGNED); + static VSigning fromBool(bool isSigned) { // Factory method + return isSigned ? VSigning{SIGNED} : VSigning{UNSIGNED}; } - explicit inline VSigning(int _e) + explicit VSigning(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } - inline bool isSigned() const { return m_e == SIGNED; } - inline bool isNosign() const { return m_e == NOSIGN; } + constexpr operator en() const { return m_e; } + bool isSigned() const { return m_e == SIGNED; } + bool isNosign() const { return m_e == NOSIGN; } // No isUnsigned() as it's ambiguous if NOSIGN should be included or not. }; -inline bool operator==(const VSigning& lhs, const VSigning& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VSigning& lhs, VSigning::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VSigning::en lhs, const VSigning& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const VSigning& lhs, const VSigning& rhs) { return lhs.m_e == rhs.m_e; } +constexpr bool operator==(const VSigning& lhs, VSigning::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(VSigning::en lhs, const VSigning& rhs) { return lhs == rhs.m_e; } inline std::ostream& operator<<(std::ostream& os, const VSigning& rhs) { return os << rhs.ascii(); } -//###################################################################### +// ###################################################################### class VPragmaType final { public: @@ -236,22 +236,22 @@ public: ENUM_SIZE }; enum en m_e; - inline VPragmaType() + VPragmaType() : m_e{ILLEGAL} {} // cppcheck-suppress noExplicitConstructor - inline VPragmaType(en _e) + constexpr VPragmaType(en _e) : m_e{_e} {} - explicit inline VPragmaType(int _e) + explicit VPragmaType(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } }; -inline bool operator==(const VPragmaType& lhs, const VPragmaType& rhs) { +constexpr bool operator==(const VPragmaType& lhs, const VPragmaType& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VPragmaType& lhs, VPragmaType::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VPragmaType::en lhs, const VPragmaType& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const VPragmaType& lhs, VPragmaType::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(VPragmaType::en lhs, const VPragmaType& rhs) { return lhs == rhs.m_e; } -//###################################################################### +// ###################################################################### class VEdgeType final { public: @@ -324,20 +324,22 @@ public: } return false; } - inline VEdgeType() + VEdgeType() : m_e{ET_ILLEGAL} {} // cppcheck-suppress noExplicitConstructor - inline VEdgeType(en _e) + constexpr VEdgeType(en _e) : m_e{_e} {} - explicit inline VEdgeType(int _e) + explicit VEdgeType(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } }; -inline bool operator==(const VEdgeType& lhs, const VEdgeType& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VEdgeType& lhs, VEdgeType::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VEdgeType::en lhs, const VEdgeType& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const VEdgeType& lhs, const VEdgeType& rhs) { + return lhs.m_e == rhs.m_e; +} +constexpr bool operator==(const VEdgeType& lhs, VEdgeType::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(VEdgeType::en lhs, const VEdgeType& rhs) { return lhs == rhs.m_e; } -//###################################################################### +// ###################################################################### class VAttrType final { public: @@ -405,20 +407,22 @@ public: // clang-format on return names[m_e]; } - inline VAttrType() + VAttrType() : m_e{ILLEGAL} {} // cppcheck-suppress noExplicitConstructor - inline VAttrType(en _e) + constexpr VAttrType(en _e) : m_e{_e} {} - explicit inline VAttrType(int _e) + explicit VAttrType(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } }; -inline bool operator==(const VAttrType& lhs, const VAttrType& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VAttrType& lhs, VAttrType::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VAttrType::en lhs, const VAttrType& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const VAttrType& lhs, const VAttrType& rhs) { + return lhs.m_e == rhs.m_e; +} +constexpr bool operator==(const VAttrType& lhs, VAttrType::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(VAttrType::en lhs, const VAttrType& rhs) { return lhs == rhs.m_e; } -//###################################################################### +// ###################################################################### class VBasicDTypeKwd final { public: @@ -467,18 +471,19 @@ public: return names[m_e]; } static void selfTest() { - UASSERT(0 == strcmp(VBasicDTypeKwd(_ENUM_MAX).ascii(), " MAX"), "SelfTest: Enum mismatch"); - UASSERT(0 == strcmp(VBasicDTypeKwd(_ENUM_MAX).dpiType(), " MAX"), + UASSERT(0 == std::strcmp(VBasicDTypeKwd{_ENUM_MAX}.ascii(), " MAX"), + "SelfTest: Enum mismatch"); + UASSERT(0 == std::strcmp(VBasicDTypeKwd{_ENUM_MAX}.dpiType(), " MAX"), "SelfTest: Enum mismatch"); } - inline VBasicDTypeKwd() + VBasicDTypeKwd() : m_e{UNKNOWN} {} // cppcheck-suppress noExplicitConstructor - inline VBasicDTypeKwd(en _e) + constexpr VBasicDTypeKwd(en _e) : m_e{_e} {} - explicit inline VBasicDTypeKwd(int _e) + explicit VBasicDTypeKwd(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } int width() const { switch (m_e) { case BIT: return 1; // scalar, can't bit extract unless ranged @@ -559,13 +564,13 @@ public: } } }; -inline bool operator==(const VBasicDTypeKwd& lhs, const VBasicDTypeKwd& rhs) { +constexpr bool operator==(const VBasicDTypeKwd& lhs, const VBasicDTypeKwd& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VBasicDTypeKwd& lhs, VBasicDTypeKwd::en rhs) { +constexpr bool operator==(const VBasicDTypeKwd& lhs, VBasicDTypeKwd::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VBasicDTypeKwd::en lhs, const VBasicDTypeKwd& rhs) { +constexpr bool operator==(VBasicDTypeKwd::en lhs, const VBasicDTypeKwd& rhs) { return lhs == rhs.m_e; } @@ -575,14 +580,14 @@ class VDirection final { public: enum en : uint8_t { NONE, INPUT, OUTPUT, INOUT, REF, CONSTREF }; enum en m_e; - inline VDirection() + VDirection() : m_e{NONE} {} // cppcheck-suppress noExplicitConstructor - inline VDirection(en _e) + constexpr VDirection(en _e) : m_e{_e} {} - explicit inline VDirection(int _e) + explicit VDirection(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } const char* ascii() const { static const char* const names[] = {"NONE", "INPUT", "OUTPUT", "INOUT", "REF", "CONSTREF"}; return names[m_e]; @@ -606,14 +611,16 @@ public: bool isWritable() const { return m_e == OUTPUT || m_e == INOUT || m_e == REF; } bool isRefOrConstRef() const { return m_e == REF || m_e == CONSTREF; } }; -inline bool operator==(const VDirection& lhs, const VDirection& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VDirection& lhs, VDirection::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VDirection::en lhs, const VDirection& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const VDirection& lhs, const VDirection& rhs) { + return lhs.m_e == rhs.m_e; +} +constexpr bool operator==(const VDirection& lhs, VDirection::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(VDirection::en lhs, const VDirection& rhs) { return lhs == rhs.m_e; } inline std::ostream& operator<<(std::ostream& os, const VDirection& rhs) { return os << rhs.ascii(); } -//###################################################################### +// ###################################################################### /// Boolean or unknown class VBoolOrUnknown final { @@ -621,12 +628,12 @@ public: enum en : uint8_t { BU_FALSE = 0, BU_TRUE = 1, BU_UNKNOWN = 2, _ENUM_END }; enum en m_e; // CONSTRUCTOR - note defaults to *UNKNOWN* - inline VBoolOrUnknown() + VBoolOrUnknown() : m_e{BU_UNKNOWN} {} // cppcheck-suppress noExplicitConstructor - inline VBoolOrUnknown(en _e) + constexpr VBoolOrUnknown(en _e) : m_e{_e} {} - explicit inline VBoolOrUnknown(int _e) + explicit VBoolOrUnknown(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning const char* ascii() const { static const char* const names[] = {"FALSE", "TRUE", "UNK"}; @@ -639,13 +646,13 @@ public: bool unknown() const { return m_e == BU_UNKNOWN; } void setTrueOrFalse(bool flag) { m_e = flag ? BU_TRUE : BU_FALSE; } }; -inline bool operator==(const VBoolOrUnknown& lhs, const VBoolOrUnknown& rhs) { +constexpr bool operator==(const VBoolOrUnknown& lhs, const VBoolOrUnknown& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VBoolOrUnknown& lhs, VBoolOrUnknown::en rhs) { +constexpr bool operator==(const VBoolOrUnknown& lhs, VBoolOrUnknown::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VBoolOrUnknown::en lhs, const VBoolOrUnknown& rhs) { +constexpr bool operator==(VBoolOrUnknown::en lhs, const VBoolOrUnknown& rhs) { return lhs == rhs.m_e; } inline std::ostream& operator<<(std::ostream& os, const VBoolOrUnknown& rhs) { @@ -660,12 +667,12 @@ public: enum en : uint8_t { JOIN = 0, JOIN_ANY = 1, JOIN_NONE = 2 }; enum en m_e; // CONSTRUCTOR - note defaults to *UNKNOWN* - inline VJoinType() + VJoinType() : m_e{JOIN} {} // cppcheck-suppress noExplicitConstructor - inline VJoinType(en _e) + constexpr VJoinType(en _e) : m_e{_e} {} - explicit inline VJoinType(int _e) + explicit VJoinType(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning const char* ascii() const { static const char* const names[] = {"JOIN", "JOIN_ANY", "JOIN_NONE"}; @@ -679,14 +686,16 @@ public: bool joinAny() const { return m_e == JOIN_ANY; } bool joinNone() const { return m_e == JOIN_NONE; } }; -inline bool operator==(const VJoinType& lhs, const VJoinType& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VJoinType& lhs, VJoinType::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VJoinType::en lhs, const VJoinType& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const VJoinType& lhs, const VJoinType& rhs) { + return lhs.m_e == rhs.m_e; +} +constexpr bool operator==(const VJoinType& lhs, VJoinType::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(VJoinType::en lhs, const VJoinType& rhs) { return lhs == rhs.m_e; } inline std::ostream& operator<<(std::ostream& os, const VJoinType& rhs) { return os << rhs.ascii(); } -//###################################################################### +// ###################################################################### class VVarType final { public: @@ -713,14 +722,14 @@ public: MEMBER }; enum en m_e; - inline VVarType() + VVarType() : m_e{UNKNOWN} {} // cppcheck-suppress noExplicitConstructor - inline VVarType(en _e) + constexpr VVarType(en _e) : m_e{_e} {} - explicit inline VVarType(int _e) + explicit VVarType(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } const char* ascii() const { static const char* const names[] = { "?", "GPARAM", "LPARAM", "GENVAR", "VAR", "SUPPLY0", "SUPPLY1", @@ -732,6 +741,10 @@ public: return (m_e == WIRE || m_e == WREAL || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1 || m_e == PORT || m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == VAR); } + bool isNet() const { + return (m_e == WIRE || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1 + || m_e == SUPPLY0 || m_e == SUPPLY1); + } bool isContAssignable() const { // In Verilog, always ok in SystemVerilog return (m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == WIRE || m_e == WREAL || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1 @@ -747,28 +760,28 @@ public: return (m_e == BLOCKTEMP || m_e == MODULETEMP || m_e == STMTTEMP || m_e == XTEMP); } }; -inline bool operator==(const VVarType& lhs, const VVarType& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VVarType& lhs, VVarType::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VVarType::en lhs, const VVarType& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const VVarType& lhs, const VVarType& rhs) { return lhs.m_e == rhs.m_e; } +constexpr bool operator==(const VVarType& lhs, VVarType::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(VVarType::en lhs, const VVarType& rhs) { return lhs == rhs.m_e; } inline std::ostream& operator<<(std::ostream& os, const VVarType& rhs) { return os << rhs.ascii(); } -//###################################################################### +// ###################################################################### class VBranchPred final { public: enum en : uint8_t { BP_UNKNOWN = 0, BP_LIKELY, BP_UNLIKELY, _ENUM_END }; enum en m_e; // CONSTRUCTOR - note defaults to *UNKNOWN* - inline VBranchPred() + VBranchPred() : m_e{BP_UNKNOWN} {} // cppcheck-suppress noExplicitConstructor - inline VBranchPred(en _e) + constexpr VBranchPred(en _e) : m_e{_e} {} - explicit inline VBranchPred(int _e) + explicit VBranchPred(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } bool unknown() const { return m_e == BP_UNKNOWN; } bool likely() const { return m_e == BP_LIKELY; } bool unlikely() const { return m_e == BP_UNLIKELY; } @@ -786,30 +799,30 @@ public: return names[m_e]; } }; -inline bool operator==(const VBranchPred& lhs, const VBranchPred& rhs) { +constexpr bool operator==(const VBranchPred& lhs, const VBranchPred& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VBranchPred& lhs, VBranchPred::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VBranchPred::en lhs, const VBranchPred& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const VBranchPred& lhs, VBranchPred::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(VBranchPred::en lhs, const VBranchPred& rhs) { return lhs == rhs.m_e; } inline std::ostream& operator<<(std::ostream& os, const VBranchPred& rhs) { return os << rhs.ascii(); } -//###################################################################### +// ###################################################################### class VVarAttrClocker final { public: enum en : uint8_t { CLOCKER_UNKNOWN = 0, CLOCKER_YES, CLOCKER_NO, _ENUM_END }; enum en m_e; // CONSTRUCTOR - note defaults to *UNKNOWN* - inline VVarAttrClocker() + VVarAttrClocker() : m_e{CLOCKER_UNKNOWN} {} // cppcheck-suppress noExplicitConstructor - inline VVarAttrClocker(en _e) + constexpr VVarAttrClocker(en _e) : m_e{_e} {} - explicit inline VVarAttrClocker(int _e) + explicit VVarAttrClocker(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } bool unknown() const { return m_e == CLOCKER_UNKNOWN; } VVarAttrClocker invert() const { if (m_e == CLOCKER_YES) { @@ -825,13 +838,13 @@ public: return names[m_e]; } }; -inline bool operator==(const VVarAttrClocker& lhs, const VVarAttrClocker& rhs) { +constexpr bool operator==(const VVarAttrClocker& lhs, const VVarAttrClocker& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VVarAttrClocker& lhs, VVarAttrClocker::en rhs) { +constexpr bool operator==(const VVarAttrClocker& lhs, VVarAttrClocker::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VVarAttrClocker::en lhs, const VVarAttrClocker& rhs) { +constexpr bool operator==(VVarAttrClocker::en lhs, const VVarAttrClocker& rhs) { return lhs == rhs.m_e; } inline std::ostream& operator<<(std::ostream& os, const VVarAttrClocker& rhs) { @@ -844,43 +857,47 @@ class VAlwaysKwd final { public: enum en : uint8_t { ALWAYS, ALWAYS_FF, ALWAYS_LATCH, ALWAYS_COMB }; enum en m_e; - inline VAlwaysKwd() + VAlwaysKwd() : m_e{ALWAYS} {} // cppcheck-suppress noExplicitConstructor - inline VAlwaysKwd(en _e) + constexpr VAlwaysKwd(en _e) : m_e{_e} {} - explicit inline VAlwaysKwd(int _e) + explicit VAlwaysKwd(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } const char* ascii() const { static const char* const names[] = {"always", "always_ff", "always_latch", "always_comb"}; return names[m_e]; } }; -inline bool operator==(const VAlwaysKwd& lhs, const VAlwaysKwd& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VAlwaysKwd& lhs, VAlwaysKwd::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VAlwaysKwd::en lhs, const VAlwaysKwd& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const VAlwaysKwd& lhs, const VAlwaysKwd& rhs) { + return lhs.m_e == rhs.m_e; +} +constexpr bool operator==(const VAlwaysKwd& lhs, VAlwaysKwd::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(VAlwaysKwd::en lhs, const VAlwaysKwd& rhs) { return lhs == rhs.m_e; } -//###################################################################### +// ###################################################################### class VCaseType final { public: enum en : uint8_t { CT_CASE, CT_CASEX, CT_CASEZ, CT_CASEINSIDE }; enum en m_e; - inline VCaseType() + VCaseType() : m_e{CT_CASE} {} // cppcheck-suppress noExplicitConstructor - inline VCaseType(en _e) + constexpr VCaseType(en _e) : m_e{_e} {} - explicit inline VCaseType(int _e) + explicit VCaseType(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } }; -inline bool operator==(const VCaseType& lhs, const VCaseType& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VCaseType& lhs, VCaseType::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VCaseType::en lhs, const VCaseType& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const VCaseType& lhs, const VCaseType& rhs) { + return lhs.m_e == rhs.m_e; +} +constexpr bool operator==(const VCaseType& lhs, VCaseType::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(VCaseType::en lhs, const VCaseType& rhs) { return lhs == rhs.m_e; } -//###################################################################### +// ###################################################################### class VDisplayType final { public: @@ -898,11 +915,11 @@ public: VDisplayType() : m_e{DT_DISPLAY} {} // cppcheck-suppress noExplicitConstructor - VDisplayType(en _e) + constexpr VDisplayType(en _e) : m_e{_e} {} - explicit inline VDisplayType(int _e) + explicit VDisplayType(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } bool addNewline() const { return m_e != DT_WRITE; } bool needScopeTracking() const { return m_e != DT_DISPLAY && m_e != DT_WRITE; } const char* ascii() const { @@ -911,39 +928,39 @@ public: return names[m_e]; } }; -inline bool operator==(const VDisplayType& lhs, const VDisplayType& rhs) { +constexpr bool operator==(const VDisplayType& lhs, const VDisplayType& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VDisplayType& lhs, VDisplayType::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VDisplayType::en lhs, const VDisplayType& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const VDisplayType& lhs, VDisplayType::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(VDisplayType::en lhs, const VDisplayType& rhs) { return lhs == rhs.m_e; } -//###################################################################### +// ###################################################################### class VDumpCtlType final { public: enum en : uint8_t { FILE, VARS, ALL, FLUSH, LIMIT, OFF, ON }; enum en m_e; - inline VDumpCtlType() + VDumpCtlType() : m_e{ON} {} // cppcheck-suppress noExplicitConstructor - inline VDumpCtlType(en _e) + constexpr VDumpCtlType(en _e) : m_e{_e} {} - explicit inline VDumpCtlType(int _e) + explicit VDumpCtlType(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } const char* ascii() const { static const char* const names[] = {"$dumpfile", "$dumpvars", "$dumpall", "$dumpflush", "$dumplimit", "$dumpoff", "$dumpon"}; return names[m_e]; } }; -inline bool operator==(const VDumpCtlType& lhs, const VDumpCtlType& rhs) { +constexpr bool operator==(const VDumpCtlType& lhs, const VDumpCtlType& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VDumpCtlType& lhs, VDumpCtlType::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VDumpCtlType::en lhs, const VDumpCtlType& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const VDumpCtlType& lhs, VDumpCtlType::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(VDumpCtlType::en lhs, const VDumpCtlType& rhs) { return lhs == rhs.m_e; } -//###################################################################### +// ###################################################################### class VParseRefExp final { public: @@ -953,31 +970,59 @@ public: PX_TEXT // Unknown ID component }; enum en m_e; - inline VParseRefExp() + VParseRefExp() : m_e{PX_NONE} {} // cppcheck-suppress noExplicitConstructor - inline VParseRefExp(en _e) + constexpr VParseRefExp(en _e) : m_e{_e} {} - explicit inline VParseRefExp(int _e) + explicit VParseRefExp(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } const char* ascii() const { static const char* const names[] = {"", "$root", "TEXT", "PREDOT"}; return names[m_e]; } }; -inline bool operator==(const VParseRefExp& lhs, const VParseRefExp& rhs) { +constexpr bool operator==(const VParseRefExp& lhs, const VParseRefExp& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VParseRefExp& lhs, VParseRefExp::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VParseRefExp::en lhs, const VParseRefExp& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const VParseRefExp& lhs, VParseRefExp::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(VParseRefExp::en lhs, const VParseRefExp& rhs) { return lhs == rhs.m_e; } inline std::ostream& operator<<(std::ostream& os, const VParseRefExp& rhs) { return os << rhs.ascii(); } -//###################################################################### -// VNumRange - Structure containing numeric range information -// See also AstRange, which is a symbolic version of this +// ###################################################################### + +class VStrength final { +public: + enum en : uint8_t { HIGHZ, SMALL, MEDIUM, WEAK, LARGE, PULL, STRONG, SUPPLY }; + enum en m_e; + + // cppcheck-suppress noExplicitConstructor + constexpr VStrength(en strengthLevel) + : m_e(strengthLevel) {} + explicit VStrength(int _e) + : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning + constexpr operator en() const { return m_e; } + const char* ascii() const { + static const char* const names[] + = {"highz", "small", "medium", "weak", "large", "pull", "strong", "supply"}; + return names[m_e]; + } +}; +constexpr bool operator==(const VStrength& lhs, const VStrength& rhs) { + return lhs.m_e == rhs.m_e; +} +constexpr bool operator==(const VStrength& lhs, VStrength::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(VStrength::en lhs, const VStrength& rhs) { return lhs == rhs.m_e; } +inline std::ostream& operator<<(std::ostream& os, const VStrength& rhs) { + return os << rhs.ascii(); +} + +// ###################################################################### +// VNumRange - Structure containing numeric range information +// See also AstRange, which is a symbolic version of this class VNumRange final { public: @@ -1050,29 +1095,29 @@ public: INT_FWD_CLASS, // Interface (.h) needs a forward class declaration }; enum en m_e; - inline VUseType() + VUseType() : m_e{IMP_FWD_CLASS} {} // cppcheck-suppress noExplicitConstructor - inline VUseType(en _e) + constexpr VUseType(en _e) : m_e{_e} {} - explicit inline VUseType(int _e) + explicit VUseType(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning bool isInclude() const { return m_e == IMP_INCLUDE || m_e == INT_INCLUDE; } bool isFwdClass() const { return m_e == IMP_FWD_CLASS || m_e == INT_FWD_CLASS; } - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } const char* ascii() const { static const char* const names[] = {"IMP_INC", "INT_INC", "IMP_FWD", "INT_FWD"}; return names[m_e]; } }; -inline bool operator==(const VUseType& lhs, const VUseType& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VUseType& lhs, VUseType::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VUseType::en lhs, const VUseType& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const VUseType& lhs, const VUseType& rhs) { return lhs.m_e == rhs.m_e; } +constexpr bool operator==(const VUseType& lhs, VUseType::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(VUseType::en lhs, const VUseType& rhs) { return lhs == rhs.m_e; } inline std::ostream& operator<<(std::ostream& os, const VUseType& rhs) { return os << rhs.ascii(); } -//###################################################################### +// ###################################################################### class VBasicTypeKey final { public: @@ -1142,7 +1187,7 @@ public: AstNode* toNodep() const { return to(); } V3GraphVertex* toGraphVertex() const { return to(); } int toInt() const { return m_u.ui; } - static VNUser fromInt(int i) { return VNUser(i); } + static VNUser fromInt(int i) { return VNUser{i}; } }; //###################################################################### @@ -1279,23 +1324,23 @@ class VNVisitor VL_NOT_FINAL : public VNDeleter { public: /// Call visit()s on nodep - void iterate(AstNode* nodep); + inline void iterate(AstNode* nodep); /// Call visit()s on nodep - void iterateNull(AstNode* nodep); + inline void iterateNull(AstNode* nodep); /// Call visit()s on nodep's children - void iterateChildren(AstNode* nodep); + inline void iterateChildren(AstNode* nodep); /// Call visit()s on nodep's children in backp() order - void iterateChildrenBackwards(AstNode* nodep); + inline void iterateChildrenBackwards(AstNode* nodep); /// Call visit()s on const nodep's children - void iterateChildrenConst(AstNode* nodep); + inline void iterateChildrenConst(AstNode* nodep); /// Call visit()s on nodep (maybe nullptr) and nodep's nextp() list - void iterateAndNextNull(AstNode* nodep); + inline void iterateAndNextNull(AstNode* nodep); /// Call visit()s on const nodep (maybe nullptr) and nodep's nextp() list - void iterateAndNextConstNull(AstNode* nodep); + inline void iterateAndNextConstNull(AstNode* nodep); /// Call visit()s on const nodep (maybe nullptr) and nodep's nextp() list, in reverse order - void iterateAndNextConstNullBackwards(AstNode* nodep); + inline void iterateAndNextConstNullBackwards(AstNode* nodep); /// Return edited nodep; see comments in V3Ast.cpp - AstNode* iterateSubtreeReturnEdits(AstNode* nodep); + inline AstNode* iterateSubtreeReturnEdits(AstNode* nodep); virtual void visit(AstNode* nodep) = 0; #include "V3Ast__gen_visitor_decls.h" // From ./astgen @@ -1323,7 +1368,7 @@ protected: public: VNRelinker() = default; - void relink(AstNode* newp); + inline void relink(AstNode* newp); AstNode* oldp() const { return m_oldp; } void dump(std::ostream& str = std::cout) const; }; @@ -1398,25 +1443,27 @@ class AstNode VL_NOT_FINAL { AstNodeDType* m_dtypep = nullptr; // Data type of output or assignment (etc) AstNode* m_headtailp; // When at begin/end of list, the opposite end of the list FileLine* m_fileline; // Where it was declared +#ifdef VL_DEBUG + // Only keep track of the edit count in the node in the debug build. + // In the release build we will take the space saving instead. uint64_t m_editCount; // When it was last edited +#endif static uint64_t s_editCntGbl; // Global edit counter - // Global edit counter, last value for printing * near node #s - static uint64_t s_editCntLast; + static uint64_t s_editCntLast; // Last committed value of global edit counter - AstNode* m_clonep - = nullptr; // Pointer to clone of/ source of this module (for *LAST* cloneTree() ONLY) + AstNode* m_clonep = nullptr; // Pointer to clone/source of node (only for *LAST* cloneTree()) static int s_cloneCntGbl; // Count of which userp is set // This member ordering both allows 64 bit alignment and puts associated data together - VNUser m_user1u = VNUser{0}; // Contains any information the user iteration routine wants + VNUser m_user1u{0}; // Contains any information the user iteration routine wants uint32_t m_user1Cnt = 0; // Mark of when userp was set uint32_t m_user2Cnt = 0; // Mark of when userp was set - VNUser m_user2u = VNUser{0}; // Contains any information the user iteration routine wants - VNUser m_user3u = VNUser{0}; // Contains any information the user iteration routine wants + VNUser m_user2u{0}; // Contains any information the user iteration routine wants + VNUser m_user3u{0}; // Contains any information the user iteration routine wants uint32_t m_user3Cnt = 0; // Mark of when userp was set uint32_t m_user4Cnt = 0; // Mark of when userp was set - VNUser m_user4u = VNUser{0}; // Contains any information the user iteration routine wants - VNUser m_user5u = VNUser{0}; // Contains any information the user iteration routine wants + VNUser m_user4u{0}; // Contains any information the user iteration routine wants + VNUser m_user5u{0}; // Contains any information the user iteration routine wants uint32_t m_user5Cnt = 0; // Mark of when userp was set // METHODS @@ -1440,8 +1487,7 @@ class AstNode VL_NOT_FINAL { private: AstNode* cloneTreeIter(); AstNode* cloneTreeIterList(); - void checkTreeIter(AstNode* backp); - void checkTreeIterList(AstNode* backp); + void checkTreeIter(const AstNode* backp) const; bool gateTreeIter() const; static bool sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ignNext, bool gateOnly); @@ -1495,7 +1541,7 @@ protected: public: // ACCESSORS - inline VNType type() const { return m_type; } + VNType type() const { return m_type; } const char* typeName() const { return type().ascii(); } // See also prettyTypeName AstNode* nextp() const { return m_nextp; } AstNode* backp() const { return m_backp; } @@ -1577,8 +1623,8 @@ public: virtual string prettyOperatorName() const { return "operator " + prettyTypeName(); } FileLine* fileline() const { return m_fileline; } void fileline(FileLine* fl) { m_fileline = fl; } - bool width1() const; - int widthInstrs() const; + inline bool width1() const; + inline int widthInstrs() const; void didWidth(bool flag) { m_flags.didWidth = flag; } bool didWidth() const { return m_flags.didWidth; } bool didWidthAndSet() { @@ -1592,29 +1638,29 @@ public: void protect(bool flag) { m_flags.protect = flag; } // TODO stomp these width functions out, and call via dtypep() instead - int width() const; - int widthMin() const; + inline int width() const; + inline int widthMin() const; int widthMinV() const { return v3Global.widthMinUsage() == VWidthMinUsage::VERILOG_WIDTH ? widthMin() : width(); } int widthWords() const { return VL_WORDS_I(width()); } bool isQuad() const { return (width() > VL_IDATASIZE && width() <= VL_QUADSIZE); } bool isWide() const { return (width() > VL_QUADSIZE); } - bool isDouble() const; - bool isSigned() const; - bool isString() const; + inline bool isDouble() const; + inline bool isSigned() const; + inline bool isString() const; // clang-format off VNUser user1u() const { // Slows things down measurably, so disabled by default //UASSERT_STATIC(VNUser1InUse::s_userBusy, "userp set w/o busy"); - return ((m_user1Cnt==VNUser1InUse::s_userCntGbl) ? m_user1u : VNUser(0)); + return ((m_user1Cnt==VNUser1InUse::s_userCntGbl) ? m_user1u : VNUser{0}); } AstNode* user1p() const { return user1u().toNodep(); } void user1u(const VNUser& user) { m_user1u=user; m_user1Cnt=VNUser1InUse::s_userCntGbl; } - void user1p(void* userp) { user1u(VNUser(userp)); } + void user1p(void* userp) { user1u(VNUser{userp}); } int user1() const { return user1u().toInt(); } - void user1(int val) { user1u(VNUser(val)); } + void user1(int val) { user1u(VNUser{val}); } int user1Inc(int val=1) { int v=user1(); user1(v+val); return v; } int user1SetOnce() { int v=user1(); if (!v) user1(1); return v; } // Better for cache than user1Inc() static void user1ClearTree() { VNUser1InUse::clear(); } // Clear userp()'s across the entire tree @@ -1622,13 +1668,13 @@ public: VNUser user2u() const { // Slows things down measurably, so disabled by default //UASSERT_STATIC(VNUser2InUse::s_userBusy, "userp set w/o busy"); - return ((m_user2Cnt==VNUser2InUse::s_userCntGbl) ? m_user2u : VNUser(0)); + return ((m_user2Cnt==VNUser2InUse::s_userCntGbl) ? m_user2u : VNUser{0}); } AstNode* user2p() const { return user2u().toNodep(); } void user2u(const VNUser& user) { m_user2u=user; m_user2Cnt=VNUser2InUse::s_userCntGbl; } - void user2p(void* userp) { user2u(VNUser(userp)); } + void user2p(void* userp) { user2u(VNUser{userp}); } int user2() const { return user2u().toInt(); } - void user2(int val) { user2u(VNUser(val)); } + void user2(int val) { user2u(VNUser{val}); } int user2Inc(int val=1) { int v=user2(); user2(v+val); return v; } int user2SetOnce() { int v=user2(); if (!v) user2(1); return v; } // Better for cache than user2Inc() static void user2ClearTree() { VNUser2InUse::clear(); } // Clear userp()'s across the entire tree @@ -1636,13 +1682,13 @@ public: VNUser user3u() const { // Slows things down measurably, so disabled by default //UASSERT_STATIC(VNUser3InUse::s_userBusy, "userp set w/o busy"); - return ((m_user3Cnt==VNUser3InUse::s_userCntGbl) ? m_user3u : VNUser(0)); + return ((m_user3Cnt==VNUser3InUse::s_userCntGbl) ? m_user3u : VNUser{0}); } AstNode* user3p() const { return user3u().toNodep(); } void user3u(const VNUser& user) { m_user3u=user; m_user3Cnt=VNUser3InUse::s_userCntGbl; } - void user3p(void* userp) { user3u(VNUser(userp)); } + void user3p(void* userp) { user3u(VNUser{userp}); } int user3() const { return user3u().toInt(); } - void user3(int val) { user3u(VNUser(val)); } + void user3(int val) { user3u(VNUser{val}); } int user3Inc(int val=1) { int v=user3(); user3(v+val); return v; } int user3SetOnce() { int v=user3(); if (!v) user3(1); return v; } // Better for cache than user3Inc() static void user3ClearTree() { VNUser3InUse::clear(); } // Clear userp()'s across the entire tree @@ -1650,13 +1696,13 @@ public: VNUser user4u() const { // Slows things down measurably, so disabled by default //UASSERT_STATIC(VNUser4InUse::s_userBusy, "userp set w/o busy"); - return ((m_user4Cnt==VNUser4InUse::s_userCntGbl) ? m_user4u : VNUser(0)); + return ((m_user4Cnt==VNUser4InUse::s_userCntGbl) ? m_user4u : VNUser{0}); } AstNode* user4p() const { return user4u().toNodep(); } void user4u(const VNUser& user) { m_user4u=user; m_user4Cnt=VNUser4InUse::s_userCntGbl; } - void user4p(void* userp) { user4u(VNUser(userp)); } + void user4p(void* userp) { user4u(VNUser{userp}); } int user4() const { return user4u().toInt(); } - void user4(int val) { user4u(VNUser(val)); } + void user4(int val) { user4u(VNUser{val}); } int user4Inc(int val=1) { int v=user4(); user4(v+val); return v; } int user4SetOnce() { int v=user4(); if (!v) user4(1); return v; } // Better for cache than user4Inc() static void user4ClearTree() { VNUser4InUse::clear(); } // Clear userp()'s across the entire tree @@ -1664,33 +1710,37 @@ public: VNUser user5u() const { // Slows things down measurably, so disabled by default //UASSERT_STATIC(VNUser5InUse::s_userBusy, "userp set w/o busy"); - return ((m_user5Cnt==VNUser5InUse::s_userCntGbl) ? m_user5u : VNUser(0)); + return ((m_user5Cnt==VNUser5InUse::s_userCntGbl) ? m_user5u : VNUser{0}); } AstNode* user5p() const { return user5u().toNodep(); } void user5u(const VNUser& user) { m_user5u=user; m_user5Cnt=VNUser5InUse::s_userCntGbl; } - void user5p(void* userp) { user5u(VNUser(userp)); } + void user5p(void* userp) { user5u(VNUser{userp}); } int user5() const { return user5u().toInt(); } - void user5(int val) { user5u(VNUser(val)); } + void user5(int val) { user5u(VNUser{val}); } int user5Inc(int val=1) { int v=user5(); user5(v+val); return v; } int user5SetOnce() { int v=user5(); if (!v) user5(1); return v; } // Better for cache than user5Inc() static void user5ClearTree() { VNUser5InUse::clear(); } // Clear userp()'s across the entire tree // clang-format on +#ifdef VL_DEBUG uint64_t editCount() const { return m_editCount; } void editCountInc() { m_editCount = ++s_editCntGbl; // Preincrement, so can "watch AstNode::s_editCntGbl=##" } +#else + void editCountInc() { ++s_editCntGbl; } +#endif static uint64_t editCountLast() { return s_editCntLast; } static uint64_t editCountGbl() { return s_editCntGbl; } static void editCountSetLast() { s_editCntLast = editCountGbl(); } // ACCESSORS for specific types // Alas these can't be virtual or they break when passed a nullptr - bool isZero() const; - bool isOne() const; - bool isNeqZero() const; - bool isAllOnes() const; - bool isAllOnesV() const; // Verilog width rules apply + inline bool isZero() const; + inline bool isOne() const; + inline bool isNeqZero() const; + inline bool isAllOnes() const; + inline bool isAllOnesV() const; // Verilog width rules apply // METHODS - data type changes especially for initial creation void dtypep(AstNodeDType* nodep) { @@ -1759,16 +1809,17 @@ public: // METHODS - Tree modifications // Returns nodep, adds newp to end of nodep's list - static AstNode* addNext(AstNode* nodep, AstNode* newp); - // Returns nodep, adds newp (maybe nullptr) to end of nodep's list - static AstNode* addNextNull(AstNode* nodep, AstNode* newp); - inline AstNode* addNext(AstNode* newp) { return addNext(this, newp); } - inline AstNode* addNextNull(AstNode* newp) { return addNextNull(this, newp); } - void addNextHere(AstNode* newp); // Insert newp at this->nextp - void addPrev(AstNode* newp) { - replaceWith(newp); - newp->addNext(this); + template + static T_NodeResult* addNext(T_NodeResult* nodep, T_NodeNext* newp) { + static_assert(std::is_base_of::value, + "'T_NodeResult' must be a subtype of AstNode"); + static_assert(std::is_base_of::value, + "'T_NodeNext' must be a subtype of 'T_NodeResult'"); + return static_cast(addNext(nodep, newp)); } + inline AstNode* addNext(AstNode* newp); + inline void addPrev(AstNode* newp); + void addNextHere(AstNode* newp); // Insert newp at this->nextp void addHereThisAsNext(AstNode* newp); // Adds at old place of this, this becomes next void replaceWith(AstNode* newp); // Replace current node in tree with new node AstNode* unlinkFrBack(VNRelinker* linkerp @@ -1791,11 +1842,13 @@ public: } AstNode* cloneTree(bool cloneNextLink); // Not const, as sets clonep() on original nodep bool gateTree() { return gateTreeIter(); } // Is tree isGateOptimizable? - bool sameTree(const AstNode* node2p) const; // Does tree of this == node2p? + inline bool sameTree(const AstNode* node2p) const; // Does tree of this == node2p? // Does tree of this == node2p?, not allowing non-isGateOptimizable - bool sameGateTree(const AstNode* node2p) const; + inline bool sameGateTree(const AstNode* node2p) const; void deleteTree(); // Always deletes the next link - void checkTree(); // User Interface version + void checkTree() const { + if (v3Global.opt.debugCheck()) checkTreeIter(backp()); + } void checkIter() const; void dumpPtrs(std::ostream& os = std::cout) const; void dumpTree(std::ostream& os = std::cout, const string& indent = " ", @@ -1891,7 +1944,7 @@ private: public: // For use via the VN_IS macro only template - inline static bool privateIs(const AstNode* nodep) { + static bool privateIs(const AstNode* nodep) { static_assert(!uselessCast(), "Unnecessary VN_IS, node known to have target type."); static_assert(!impossibleCast(), "Unnecessary VN_IS, node cannot be this type."); return nodep && privateTypeTest(nodep); @@ -1899,14 +1952,14 @@ public: // For use via the VN_CAST macro only template - inline static T* privateCast(AstNode* nodep) { + static T* privateCast(AstNode* nodep) { static_assert(!uselessCast(), "Unnecessary VN_CAST, node known to have target type."); static_assert(!impossibleCast(), "Unnecessary VN_CAST, node cannot be this type."); return nodep && privateTypeTest(nodep) ? reinterpret_cast(nodep) : nullptr; } template - inline static const T* privateCast(const AstNode* nodep) { + static const T* privateCast(const AstNode* nodep) { static_assert(!uselessCast(), "Unnecessary VN_CAST, node known to have target type."); static_assert(!impossibleCast(), "Unnecessary VN_CAST, node cannot be this type."); @@ -1915,7 +1968,7 @@ public: // For use via the VN_AS macro only template - inline static T* privateAs(AstNode* nodep) { + static T* privateAs(AstNode* nodep) { static_assert(!uselessCast(), "Unnecessary VN_AS, node known to have target type."); static_assert(!impossibleCast(), "Unnecessary VN_AS, node cannot be this type."); UASSERT_OBJ(!nodep || privateTypeTest(nodep), nodep, @@ -1924,7 +1977,7 @@ public: return reinterpret_cast(nodep); } template - inline static const T* privateAs(const AstNode* nodep) { + static const T* privateAs(const AstNode* nodep) { static_assert(!uselessCast(), "Unnecessary VN_AS, node known to have target type."); static_assert(!impossibleCast(), "Unnecessary VN_AS, node cannot be this type."); UASSERT_OBJ(!nodep || privateTypeTest(nodep), nodep, @@ -2056,6 +2109,17 @@ public: } }; +// Forward declarations of specializations defined in V3Ast.cpp +template <> +AstNode* AstNode::addNext(AstNode* nodep, AstNode* newp); + +// Inline method implementations +AstNode* AstNode::addNext(AstNode* newp) { return addNext(this, newp); } +void AstNode::addPrev(AstNode* newp) { + replaceWith(newp); + newp->addNext(this); +} + // Specialisations of privateTypeTest #include "V3Ast__gen_impl.h" // From ./astgen @@ -2125,7 +2189,7 @@ void AstNode::foreachImpl(ConstCorrectAstNode* nodep, const std::function constexpr int prefetchDistance = 2; // Grow stack to given size - const auto grow = [&](size_t size) VL_ATTR_ALWINLINE { + const auto grow = [&](size_t size) { const ptrdiff_t occupancy = topp - basep; stack.resize(size); basep = stack.data() + prefetchDistance; @@ -2141,7 +2205,7 @@ void AstNode::foreachImpl(ConstCorrectAstNode* nodep, const std::function for (int i = -prefetchDistance; i; ++i) basep[i] = nodep; // Visit given node, enqueue children for traversal - const auto visit = [&](Node* currp) VL_ATTR_ALWINLINE { + const auto visit = [&](Node* currp) { // Type test this node if (AstNode::privateTypeTest(currp)) { // Call the client function @@ -2206,7 +2270,7 @@ bool AstNode::predicateImpl(ConstCorrectAstNode* nodep, constexpr int prefetchDistance = 2; // Grow stack to given size - const auto grow = [&](size_t size) VL_ATTR_ALWINLINE { + const auto grow = [&](size_t size) { const ptrdiff_t occupancy = topp - basep; stack.resize(size); basep = stack.data() + prefetchDistance; @@ -2222,7 +2286,7 @@ bool AstNode::predicateImpl(ConstCorrectAstNode* nodep, for (int i = -prefetchDistance; i; ++i) basep[i] = nodep; // Visit given node, enqueue children for traversal, return true if result determined. - const auto visit = [&](Node* currp) VL_ATTR_ALWINLINE { + const auto visit = [&](Node* currp) { // Type test this node if (AstNode::privateTypeTest(currp)) { // Call the client function @@ -2275,7 +2339,7 @@ inline std::ostream& operator<<(std::ostream& os, const AstNode* rhs) { } return os; } -inline void VNRelinker::relink(AstNode* newp) { newp->AstNode::relink(this); } +void VNRelinker::relink(AstNode* newp) { newp->AstNode::relink(this); } //###################################################################### @@ -2319,1111 +2383,46 @@ struct std::equal_to> final { } }; -//###################################################################### -//=== AstNode* : Derived generic node types - -#define ASTNODE_BASE_FUNCS(name) \ - virtual ~Ast##name() override = default; \ - static Ast##name* cloneTreeNull(Ast##name* nodep, bool cloneNextLink) { \ - return nodep ? nodep->cloneTree(cloneNextLink) : nullptr; \ - } \ - Ast##name* cloneTree(bool cloneNext) { \ - return static_cast(AstNode::cloneTree(cloneNext)); \ - } \ - Ast##name* clonep() const { return static_cast(AstNode::clonep()); } - -class AstNodeMath VL_NOT_FINAL : public AstNode { - // Math -- anything that's part of an expression tree -protected: - AstNodeMath(VNType t, FileLine* fl) - : AstNode{t, fl} {} - -public: - ASTNODE_BASE_FUNCS(NodeMath) - // METHODS - virtual void dump(std::ostream& str) const override; - virtual bool hasDType() const override { return true; } - virtual string emitVerilog() = 0; /// Format string for verilog writing; see V3EmitV - // For documentation on emitC format see EmitCFunc::emitOpName - virtual string emitC() = 0; - virtual string emitSimpleOperator() { return ""; } // "" means not ok to use - virtual bool emitCheckMaxWords() { return false; } // Check VL_MULS_MAX_WORDS - virtual bool cleanOut() const = 0; // True if output has extra upper bits zero - // Someday we will generically support data types on every math node - // Until then isOpaque indicates we shouldn't constant optimize this node type - bool isOpaque() const { return VN_IS(this, CvtPackString); } -}; - -class AstNodeTermop VL_NOT_FINAL : public AstNodeMath { - // Terminal operator -- a operator with no "inputs" -protected: - AstNodeTermop(VNType t, FileLine* fl) - : AstNodeMath{t, fl} {} - -public: - ASTNODE_BASE_FUNCS(NodeTermop) - // Know no children, and hot function, so skip iterator for speed - // See checkTreeIter also that asserts no children - // cppcheck-suppress functionConst - void iterateChildren(VNVisitor& v) {} - virtual void dump(std::ostream& str) const override; -}; - -class AstNodeUniop VL_NOT_FINAL : public AstNodeMath { - // Unary math -protected: - AstNodeUniop(VNType t, FileLine* fl, AstNode* lhsp) - : AstNodeMath{t, fl} { - dtypeFrom(lhsp); - setOp1p(lhsp); - } - -public: - ASTNODE_BASE_FUNCS(NodeUniop) - AstNode* lhsp() const { return op1p(); } - void lhsp(AstNode* nodep) { return setOp1p(nodep); } - // METHODS - virtual void dump(std::ostream& str) const override; - // Set out to evaluation of a AstConst'ed lhs - virtual void numberOperate(V3Number& out, const V3Number& lhs) = 0; - virtual bool cleanLhs() const = 0; - virtual bool sizeMattersLhs() const = 0; // True if output result depends on lhs size - virtual bool doubleFlavor() const { return false; } // D flavor of nodes with both flavors? - // Signed flavor of nodes with both flavors? - virtual bool signedFlavor() const { return false; } - virtual bool stringFlavor() const { return false; } // N flavor of nodes with both flavors? - virtual int instrCount() const override { return widthInstrs(); } - virtual bool same(const AstNode*) const override { return true; } -}; - -class AstNodeBiop VL_NOT_FINAL : public AstNodeMath { - // Binary math -protected: - AstNodeBiop(VNType t, FileLine* fl, AstNode* lhs, AstNode* rhs) - : AstNodeMath{t, fl} { - setOp1p(lhs); - setOp2p(rhs); - } - -public: - ASTNODE_BASE_FUNCS(NodeBiop) - // Clone single node, just get same type back. - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) = 0; - // ACCESSORS - AstNode* lhsp() const { return op1p(); } - AstNode* rhsp() const { return op2p(); } - void lhsp(AstNode* nodep) { return setOp1p(nodep); } - void rhsp(AstNode* nodep) { return setOp2p(nodep); } - // METHODS - // Set out to evaluation of a AstConst'ed - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) = 0; - virtual bool cleanLhs() const = 0; // True if LHS must have extra upper bits zero - virtual bool cleanRhs() const = 0; // True if RHS must have extra upper bits zero - virtual bool sizeMattersLhs() const = 0; // True if output result depends on lhs size - virtual bool sizeMattersRhs() const = 0; // True if output result depends on rhs size - virtual bool doubleFlavor() const { return false; } // D flavor of nodes with both flavors? - // Signed flavor of nodes with both flavors? - virtual bool signedFlavor() const { return false; } - virtual bool stringFlavor() const { return false; } // N flavor of nodes with both flavors? - virtual int instrCount() const override { return widthInstrs(); } - virtual bool same(const AstNode*) const override { return true; } -}; - -class AstNodeTriop VL_NOT_FINAL : public AstNodeMath { - // Trinary math -protected: - AstNodeTriop(VNType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths) - : AstNodeMath{t, fl} { - setOp1p(lhs); - setOp2p(rhs); - setOp3p(ths); - } - -public: - ASTNODE_BASE_FUNCS(NodeTriop) - AstNode* lhsp() const { return op1p(); } - AstNode* rhsp() const { return op2p(); } - AstNode* thsp() const { return op3p(); } - void lhsp(AstNode* nodep) { return setOp1p(nodep); } - void rhsp(AstNode* nodep) { return setOp2p(nodep); } - void thsp(AstNode* nodep) { return setOp3p(nodep); } - // METHODS - virtual void dump(std::ostream& str) const override; - // Set out to evaluation of a AstConst'ed - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, - const V3Number& ths) - = 0; - virtual bool cleanLhs() const = 0; // True if LHS must have extra upper bits zero - virtual bool cleanRhs() const = 0; // True if RHS must have extra upper bits zero - virtual bool cleanThs() const = 0; // True if THS must have extra upper bits zero - virtual bool sizeMattersLhs() const = 0; // True if output result depends on lhs size - virtual bool sizeMattersRhs() const = 0; // True if output result depends on rhs size - virtual bool sizeMattersThs() const = 0; // True if output result depends on ths size - virtual int instrCount() const override { return widthInstrs(); } - virtual bool same(const AstNode*) const override { return true; } -}; - -class AstNodeQuadop VL_NOT_FINAL : public AstNodeMath { - // Quaternary math -protected: - AstNodeQuadop(VNType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths, AstNode* fhs) - : AstNodeMath{t, fl} { - setOp1p(lhs); - setOp2p(rhs); - setOp3p(ths); - setOp4p(fhs); - } - -public: - ASTNODE_BASE_FUNCS(NodeQuadop) - AstNode* lhsp() const { return op1p(); } - AstNode* rhsp() const { return op2p(); } - AstNode* thsp() const { return op3p(); } - AstNode* fhsp() const { return op4p(); } - void lhsp(AstNode* nodep) { return setOp1p(nodep); } - void rhsp(AstNode* nodep) { return setOp2p(nodep); } - void thsp(AstNode* nodep) { return setOp3p(nodep); } - void fhsp(AstNode* nodep) { return setOp4p(nodep); } - // METHODS - // Set out to evaluation of a AstConst'ed - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, - const V3Number& ths, const V3Number& fhs) - = 0; - virtual bool cleanLhs() const = 0; // True if LHS must have extra upper bits zero - virtual bool cleanRhs() const = 0; // True if RHS must have extra upper bits zero - virtual bool cleanThs() const = 0; // True if THS must have extra upper bits zero - virtual bool cleanFhs() const = 0; // True if THS must have extra upper bits zero - virtual bool sizeMattersLhs() const = 0; // True if output result depends on lhs size - virtual bool sizeMattersRhs() const = 0; // True if output result depends on rhs size - virtual bool sizeMattersThs() const = 0; // True if output result depends on ths size - virtual bool sizeMattersFhs() const = 0; // True if output result depends on ths size - virtual int instrCount() const override { return widthInstrs(); } - virtual bool same(const AstNode*) const override { return true; } -}; - -class AstNodeBiCom VL_NOT_FINAL : public AstNodeBiop { - // Binary math with commutative properties -protected: - AstNodeBiCom(VNType t, FileLine* fl, AstNode* lhs, AstNode* rhs) - : AstNodeBiop{t, fl, lhs, rhs} {} - -public: - ASTNODE_BASE_FUNCS(NodeBiCom) -}; - -class AstNodeBiComAsv VL_NOT_FINAL : public AstNodeBiCom { - // Binary math with commutative & associative properties -protected: - AstNodeBiComAsv(VNType t, FileLine* fl, AstNode* lhs, AstNode* rhs) - : AstNodeBiCom{t, fl, lhs, rhs} {} - -public: - ASTNODE_BASE_FUNCS(NodeBiComAsv) -}; - -class AstNodeCond VL_NOT_FINAL : public AstNodeTriop { -protected: - AstNodeCond(VNType t, FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p) - : AstNodeTriop{t, fl, condp, expr1p, expr2p} { - if (expr1p) { - dtypeFrom(expr1p); - } else if (expr2p) { - dtypeFrom(expr2p); - } - } - -public: - ASTNODE_BASE_FUNCS(NodeCond) - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, - const V3Number& ths) override; - AstNode* condp() const { return op1p(); } // op1 = Condition - AstNode* expr1p() const { return op2p(); } // op2 = If true... - AstNode* expr2p() const { return op3p(); } // op3 = If false... - virtual string emitVerilog() override { return "%k(%l %f? %r %k: %t)"; } - virtual string emitC() override { return "VL_COND_%nq%lq%rq%tq(%nw, %P, %li, %ri, %ti)"; } - virtual bool cleanOut() const override { return false; } // clean if e1 & e2 clean - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return false; } - virtual bool cleanThs() const override { return false; } // Propagates up - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool sizeMattersThs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } - virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) = 0; -}; - -class AstNodeBlock VL_NOT_FINAL : public AstNode { - // A Begin/fork block - // Parents: statement - // Children: statements -private: - string m_name; // Name of block - bool m_unnamed; // Originally unnamed (name change does not affect this) -protected: - AstNodeBlock(VNType t, FileLine* fl, const string& name, AstNode* stmtsp) - : AstNode{t, fl} - , m_name{name} { - addNOp1p(stmtsp); - m_unnamed = (name == ""); - } - -public: - ASTNODE_BASE_FUNCS(NodeBlock) - virtual void dump(std::ostream& str) const override; - virtual string name() const override { return m_name; } // * = Block name - virtual void name(const string& name) override { m_name = name; } - // op1 = Statements - AstNode* stmtsp() const { return op1p(); } // op1 = List of statements - void addStmtsp(AstNode* nodep) { addNOp1p(nodep); } - bool unnamed() const { return m_unnamed; } - bool isFirstInMyListOfStatements(AstNode* nodep) const override { return nodep == stmtsp(); } -}; - -class AstNodePreSel VL_NOT_FINAL : public AstNode { - // Something that becomes an AstSel -protected: - AstNodePreSel(VNType t, FileLine* fl, AstNode* fromp, AstNode* rhs, AstNode* ths) - : AstNode{t, fl} { - setOp1p(fromp); - setOp2p(rhs); - setNOp3p(ths); - } - -public: - ASTNODE_BASE_FUNCS(NodePreSel) - AstNode* fromp() const { return op1p(); } - AstNode* rhsp() const { return op2p(); } - AstNode* thsp() const { return op3p(); } - AstAttrOf* attrp() const { return VN_AS(op4p(), AttrOf); } - void fromp(AstNode* nodep) { return setOp1p(nodep); } - void rhsp(AstNode* nodep) { return setOp2p(nodep); } - void thsp(AstNode* nodep) { return setOp3p(nodep); } - void attrp(AstAttrOf* nodep) { return setOp4p(reinterpret_cast(nodep)); } - // METHODS - virtual bool same(const AstNode*) const override { return true; } -}; - -class AstNodeProcedure VL_NOT_FINAL : public AstNode { - // IEEE procedure: initial, final, always -protected: - AstNodeProcedure(VNType t, FileLine* fl, AstNode* bodysp) - : AstNode{t, fl} { - addNOp2p(bodysp); - } - -public: - ASTNODE_BASE_FUNCS(NodeProcedure) - // METHODS - virtual void dump(std::ostream& str) const override; - AstNode* bodysp() const { return op2p(); } // op2 = Statements to evaluate - void addStmtp(AstNode* nodep) { addOp2p(nodep); } - bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); } -}; - -class AstNodeStmt VL_NOT_FINAL : public AstNode { - // Statement -- anything that's directly under a function - bool m_statement; // Really a statement (e.g. not a function with return) -protected: - AstNodeStmt(VNType t, FileLine* fl, bool statement = true) - : AstNode{t, fl} - , m_statement{statement} {} - -public: - ASTNODE_BASE_FUNCS(NodeStmt) - // METHODS - bool isStatement() const { return m_statement; } // Really a statement - void statement(bool flag) { m_statement = flag; } - virtual void addNextStmt(AstNode* newp, - AstNode* belowp) override; // Stop statement searchback here - virtual void addBeforeStmt(AstNode* newp, - AstNode* belowp) override; // Stop statement searchback here - virtual void dump(std::ostream& str = std::cout) const override; -}; - -class AstNodeAssign VL_NOT_FINAL : public AstNodeStmt { -protected: - AstNodeAssign(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp, - AstNode* timingControlp = nullptr) - : AstNodeStmt{t, fl} { - setOp1p(rhsp); - setOp2p(lhsp); - addNOp3p(timingControlp); - dtypeFrom(lhsp); - } - -public: - ASTNODE_BASE_FUNCS(NodeAssign) - // Clone single node, just get same type back. - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) = 0; - // So iteration hits the RHS which is "earlier" in execution order, it's op1, not op2 - AstNode* rhsp() const { return op1p(); } // op1 = Assign from - AstNode* lhsp() const { return op2p(); } // op2 = Assign to - // op3 = Timing controls (delays, event controls) - AstNode* timingControlp() const { return op3p(); } - void addTimingControlp(AstNode* const np) { addNOp3p(np); } - void rhsp(AstNode* np) { setOp1p(np); } - void lhsp(AstNode* np) { setOp2p(np); } - virtual bool hasDType() const override { return true; } - virtual bool cleanRhs() const { return true; } - virtual int instrCount() const override { return widthInstrs(); } - virtual bool same(const AstNode*) const override { return true; } - virtual string verilogKwd() const override { return "="; } - virtual bool brokeLhsMustBeLvalue() const = 0; -}; - -class AstNodeFor VL_NOT_FINAL : public AstNodeStmt { -protected: - AstNodeFor(VNType t, FileLine* fl, AstNode* initsp, AstNode* condp, AstNode* incsp, - AstNode* bodysp) - : AstNodeStmt{t, fl} { - addNOp1p(initsp); - setOp2p(condp); - addNOp3p(incsp); - addNOp4p(bodysp); - } - -public: - ASTNODE_BASE_FUNCS(NodeFor) - AstNode* initsp() const { return op1p(); } // op1 = initial statements - AstNode* condp() const { return op2p(); } // op2 = condition to continue - AstNode* incsp() const { return op3p(); } // op3 = increment statements - AstNode* bodysp() const { return op4p(); } // op4 = body of loop - virtual bool isGateOptimizable() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstNodeIf VL_NOT_FINAL : public AstNodeStmt { -private: - VBranchPred m_branchPred; // Branch prediction as taken/untaken? - bool m_isBoundsCheck; // True if this if node was inserted for array bounds checking -protected: - AstNodeIf(VNType t, FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp) - : AstNodeStmt{t, fl} { - setOp1p(condp); - addNOp2p(ifsp); - addNOp3p(elsesp); - isBoundsCheck(false); - } - -public: - ASTNODE_BASE_FUNCS(NodeIf) - AstNode* condp() const { return op1p(); } // op1 = condition - AstNode* ifsp() const { return op2p(); } // op2 = list of true statements - AstNode* elsesp() const { return op3p(); } // op3 = list of false statements - void condp(AstNode* newp) { setOp1p(newp); } - void addIfsp(AstNode* newp) { addOp2p(newp); } - void addElsesp(AstNode* newp) { addOp3p(newp); } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isGateDedupable() const override { return true; } - virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - void branchPred(VBranchPred flag) { m_branchPred = flag; } - VBranchPred branchPred() const { return m_branchPred; } - void isBoundsCheck(bool flag) { m_isBoundsCheck = flag; } - bool isBoundsCheck() const { return m_isBoundsCheck; } - bool isFirstInMyListOfStatements(AstNode* n) const override { - return n == ifsp() || n == elsesp(); - } -}; - -class AstNodeCase VL_NOT_FINAL : public AstNodeStmt { -protected: - AstNodeCase(VNType t, FileLine* fl, AstNode* exprp, AstNode* casesp) - : AstNodeStmt{t, fl} { - setOp1p(exprp); - addNOp2p(casesp); - } - -public: - ASTNODE_BASE_FUNCS(NodeCase) - virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } - AstNode* exprp() const { return op1p(); } // op1 = case condition - AstCaseItem* itemsp() const { - return VN_AS(op2p(), CaseItem); - } // op2 = list of case expressions - AstNode* notParallelp() const { return op3p(); } // op3 = assertion code for non-full case's - void addItemsp(AstNode* nodep) { addOp2p(nodep); } - void addNotParallelp(AstNode* nodep) { setOp3p(nodep); } -}; - -class AstNodeVarRef VL_NOT_FINAL : public AstNodeMath { - // An AstVarRef or AstVarXRef -private: - VAccess m_access; // Left hand side assignment - AstVar* m_varp; // [AfterLink] Pointer to variable itself - AstVarScope* m_varScopep = nullptr; // Varscope for hierarchy - AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy - string m_name; // Name of variable - string m_selfPointer; // Output code object pointer (e.g.: 'this') - -protected: - AstNodeVarRef(VNType t, FileLine* fl, const string& name, const VAccess& access) - : AstNodeMath{t, fl} - , m_access{access} - , m_name{name} { - varp(nullptr); - } - AstNodeVarRef(VNType t, FileLine* fl, const string& name, AstVar* varp, const VAccess& access) - : AstNodeMath{t, fl} - , m_access{access} - , m_name{name} { - // May have varp==nullptr - this->varp(varp); - } - -public: - ASTNODE_BASE_FUNCS(NodeVarRef) - virtual void dump(std::ostream& str) const override; - virtual bool hasDType() const override { return true; } - virtual const char* broken() const override; - virtual int instrCount() const override { return widthInstrs(); } - virtual void cloneRelink() override; - virtual string name() const override { return m_name; } // * = Var name - virtual void name(const string& name) override { m_name = name; } - VAccess access() const { return m_access; } - void access(const VAccess& flag) { m_access = flag; } // Avoid using this; Set in constructor - AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable - void varp(AstVar* varp); - AstVarScope* varScopep() const { return m_varScopep; } - void varScopep(AstVarScope* varscp) { m_varScopep = varscp; } - string selfPointer() const { return m_selfPointer; } - void selfPointer(const string& value) { m_selfPointer = value; } - string selfPointerProtect(bool useSelfForThis) const; - AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } - void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } - // Know no children, and hot function, so skip iterator for speed - // See checkTreeIter also that asserts no children - // cppcheck-suppress functionConst - void iterateChildren(VNVisitor& v) {} -}; - -class AstNodeText VL_NOT_FINAL : public AstNode { -private: - string m_text; - -protected: - // Node that puts text into the output stream - AstNodeText(VNType t, FileLine* fl, const string& textp) - : AstNode{t, fl} { - m_text = textp; // Copy it - } - -public: - ASTNODE_BASE_FUNCS(NodeText) - virtual void dump(std::ostream& str = std::cout) const override; - virtual bool same(const AstNode* samep) const override { - const AstNodeText* asamep = static_cast(samep); - return text() == asamep->text(); - } - const string& text() const { return m_text; } -}; - -class AstNodeDType VL_NOT_FINAL : public AstNode { - // Ideally width() would migrate to BasicDType as that's where it makes sense, - // but it's currently so prevalent in the code we leave it here. - // Note the below members are included in AstTypeTable::Key lookups -private: - int m_width; // (also in AstTypeTable::Key) Bit width of operation - int m_widthMin; // (also in AstTypeTable::Key) If unsized, bitwidth of minimum implementation - VSigning m_numeric; // (also in AstTypeTable::Key) Node is signed - // Other members - bool m_generic; // Simple globally referenced type, don't garbage collect - // Unique number assigned to each dtype during creation for IEEE matching - static int s_uniqueNum; - -protected: - // CONSTRUCTORS - AstNodeDType(VNType t, FileLine* fl) - : AstNode{t, fl} { - m_width = 0; - m_widthMin = 0; - m_generic = false; - } - -public: - ASTNODE_BASE_FUNCS(NodeDType) - // ACCESSORS - virtual void dump(std::ostream& str) const override; - virtual void dumpSmall(std::ostream& str) const; - virtual bool hasDType() const override { return true; } - /// Require VlUnpacked, instead of [] for POD elements. - /// A non-POD object is always compound, but some POD elements - /// are compound when methods calls operate on object, or when - /// under another compound-requiring object e.g. class - virtual bool isCompound() const = 0; - // (Slow) recurse down to find basic data type - virtual AstBasicDType* basicp() const = 0; - // recurses over typedefs/const/enum to next non-typeref type - virtual AstNodeDType* skipRefp() const = 0; - // recurses over typedefs to next non-typeref-or-const type - virtual AstNodeDType* skipRefToConstp() const = 0; - // recurses over typedefs/const to next non-typeref-or-enum/struct type - virtual AstNodeDType* skipRefToEnump() const = 0; - // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) - virtual int widthAlignBytes() const = 0; - // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... - virtual int widthTotalBytes() const = 0; - virtual bool maybePointedTo() const override { return true; } - // Iff has a non-null refDTypep(), as generic node function - virtual AstNodeDType* virtRefDTypep() const { return nullptr; } - // Iff has refDTypep(), set as generic node function - virtual void virtRefDTypep(AstNodeDType* nodep) {} - // Iff has a non-null second dtypep, as generic node function - virtual AstNodeDType* virtRefDType2p() const { return nullptr; } - // Iff has second dtype, set as generic node function - virtual void virtRefDType2p(AstNodeDType* nodep) {} - // Assignable equivalence. Call skipRefp() on this and samep before calling - virtual bool similarDType(AstNodeDType* samep) const = 0; - // Iff has a non-null subDTypep(), as generic node function - virtual AstNodeDType* subDTypep() const { return nullptr; } - virtual bool isFourstate() const; - // Ideally an IEEE $typename - virtual string prettyDTypeName() const { return prettyTypeName(); } - string prettyDTypeNameQ() const { return "'" + prettyDTypeName() + "'"; } - // - // Changing the width may confuse the data type resolution, so must clear - // TypeTable cache after use. - void widthForce(int width, int widthMin) { - m_width = width; - m_widthMin = widthMin; - } - // For backward compatibility inherit width and signing from the subDType/base type - void widthFromSub(AstNodeDType* nodep) { - m_width = nodep->m_width; - m_widthMin = nodep->m_widthMin; - m_numeric = nodep->m_numeric; - } - // - int width() const { return m_width; } - void numeric(VSigning flag) { m_numeric = flag; } - bool isSigned() const { return m_numeric.isSigned(); } - bool isNosign() const { return m_numeric.isNosign(); } - VSigning numeric() const { return m_numeric; } - int widthWords() const { return VL_WORDS_I(width()); } - int widthMin() const { // If sized, the size, if unsized the min digits to represent it - return m_widthMin ? m_widthMin : m_width; - } - int widthPow2() const; - void widthMinFromWidth() { m_widthMin = m_width; } - bool widthSized() const { return !m_widthMin || m_widthMin == m_width; } - bool generic() const { return m_generic; } - void generic(bool flag) { m_generic = flag; } - std::pair dimensions(bool includeBasic); - uint32_t arrayUnpackedElements(); // 1, or total multiplication of all dimensions - static int uniqueNumInc() { return ++s_uniqueNum; } - const char* charIQWN() const { - return (isString() ? "N" : isWide() ? "W" : isQuad() ? "Q" : "I"); - } - string cType(const string& name, bool forFunc, bool isRef) const; - bool isLiteralType() const; // Does this represent a C++ LiteralType? (can be constexpr) - -private: - class CTypeRecursed; - CTypeRecursed cTypeRecurse(bool compound) const; -}; - -class AstNodeUOrStructDType VL_NOT_FINAL : public AstNodeDType { - // A struct or union; common handling -private: - // TYPES - using MemberNameMap = std::map; - // MEMBERS - string m_name; // Name from upper typedef, if any - bool m_packed; - bool m_isFourstate; - MemberNameMap m_members; - const int m_uniqueNum; - -protected: - AstNodeUOrStructDType(VNType t, FileLine* fl, VSigning numericUnpack) - : AstNodeDType{t, fl} - , m_uniqueNum{uniqueNumInc()} { - // VSigning::NOSIGN overloaded to indicate not packed - m_packed = (numericUnpack != VSigning::NOSIGN); - m_isFourstate = false; // V3Width computes - numeric(VSigning::fromBool(numericUnpack.isSigned())); - } - -public: - ASTNODE_BASE_FUNCS(NodeUOrStructDType) - int uniqueNum() const { return m_uniqueNum; } - virtual const char* broken() const override; - virtual void dump(std::ostream& str) const override; - virtual bool isCompound() const override { return false; } // Because don't support unpacked - // For basicp() we reuse the size to indicate a "fake" basic type of same size - virtual AstBasicDType* basicp() const override { - return (isFourstate() - ? VN_AS(findLogicRangeDType(VNumRange{width() - 1, 0}, width(), numeric()), - BasicDType) - : VN_AS(findBitRangeDType(VNumRange{width() - 1, 0}, width(), numeric()), - BasicDType)); - } - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) - virtual int widthAlignBytes() const override; - // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... - virtual int widthTotalBytes() const override; - // op1 = members - virtual bool similarDType(AstNodeDType* samep) const override { - return this == samep; // We don't compare members, require exact equivalence - } - virtual string name() const override { return m_name; } - virtual void name(const string& flag) override { m_name = flag; } - AstMemberDType* membersp() const { - return VN_AS(op1p(), MemberDType); - } // op1 = AstMember list - void addMembersp(AstNode* nodep) { addNOp1p(nodep); } - bool packed() const { return m_packed; } - // packed() but as don't support unpacked, presently all structs - static bool packedUnsup() { return true; } - void isFourstate(bool flag) { m_isFourstate = flag; } - virtual bool isFourstate() const override { return m_isFourstate; } - void clearCache() { m_members.clear(); } - void repairMemberCache(); - AstMemberDType* findMember(const string& name) const { - const auto it = m_members.find(name); - return (it == m_members.end()) ? nullptr : it->second; - } - static int lo() { return 0; } - int hi() const { return dtypep()->width() - 1; } // Packed classes look like arrays - VNumRange declRange() const { return VNumRange{hi(), lo()}; } -}; - -class AstNodeArrayDType VL_NOT_FINAL : public AstNodeDType { - // Array data type, ie "some_dtype var_name [2:0]" - // Children: DTYPE (moved to refDTypep() in V3Width) - // Children: RANGE (array bounds) -private: - AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing) - AstNode* rangenp() const { return op2p(); } // op2 = Array(s) of variable -protected: - AstNodeArrayDType(VNType t, FileLine* fl) - : AstNodeDType{t, fl} {} - -public: - ASTNODE_BASE_FUNCS(NodeArrayDType) - virtual void dump(std::ostream& str) const override; - virtual void dumpSmall(std::ostream& str) const override; - virtual const char* broken() const override { - BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) - || (!m_refDTypep && childDTypep()))); - return nullptr; - } - virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); - } - virtual bool same(const AstNode* samep) const override { - const AstNodeArrayDType* const asamep = static_cast(samep); - return (hi() == asamep->hi() && subDTypep() == asamep->subDTypep() - && rangenp()->sameTree(asamep->rangenp())); - } // HashedDT doesn't recurse, so need to check children - virtual bool similarDType(AstNodeDType* samep) const override { - const AstNodeArrayDType* const asamep = static_cast(samep); - return (asamep && type() == samep->type() && hi() == asamep->hi() - && rangenp()->sameTree(asamep->rangenp()) - && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); - } - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const override { - return m_refDTypep ? m_refDTypep : childDTypep(); - } - void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } - virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } - virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } - AstRange* rangep() const { return VN_AS(op2p(), Range); } // op2 = Array(s) of variable - void rangep(AstRange* nodep); - // METHODS - virtual AstBasicDType* basicp() const override { - return subDTypep()->basicp(); - } // (Slow) recurse down to find basic data type - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } - virtual int widthTotalBytes() const override { - return elementsConst() * subDTypep()->widthTotalBytes(); - } - int left() const; - int right() const; - int hi() const; - int lo() const; - int elementsConst() const; - VNumRange declRange() const; -}; - -class AstNodeSel VL_NOT_FINAL : public AstNodeBiop { - // Single bit range extraction, perhaps with non-constant selection or array selection -protected: - AstNodeSel(VNType t, FileLine* fl, AstNode* fromp, AstNode* bitp) - : AstNodeBiop{t, fl, fromp, bitp} {} - -public: - ASTNODE_BASE_FUNCS(NodeSel) - AstNode* fromp() const { - return op1p(); - } // op1 = Extracting what (nullptr=TBD during parsing) - void fromp(AstNode* nodep) { setOp1p(nodep); } - AstNode* bitp() const { return op2p(); } // op2 = Msb selection expression - void bitp(AstNode* nodep) { setOp2p(nodep); } - int bitConst() const; - virtual bool hasDType() const override { return true; } -}; - -class AstNodeStream VL_NOT_FINAL : public AstNodeBiop { - // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() -protected: - AstNodeStream(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : AstNodeBiop{t, fl, lhsp, rhsp} { - if (lhsp->dtypep()) dtypeSetLogicSized(lhsp->dtypep()->width(), VSigning::UNSIGNED); - } - -public: - ASTNODE_BASE_FUNCS(NodeStream) -}; - -//###################################################################### -// Tasks/functions common handling - -class AstNodeCCall VL_NOT_FINAL : public AstNodeStmt { - // A call of a C++ function, perhaps a AstCFunc or perhaps globally named - // Functions are not statements, while tasks are. AstNodeStmt needs isStatement() to deal. - AstCFunc* m_funcp; - string m_argTypes; - -protected: - AstNodeCCall(VNType t, FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) - : AstNodeStmt{t, fl, true} - , m_funcp{funcp} { - addNOp2p(argsp); - } - -public: - ASTNODE_BASE_FUNCS(NodeCCall) - virtual void dump(std::ostream& str = std::cout) const override; - virtual void cloneRelink() override; - virtual const char* broken() const override; - virtual int instrCount() const override { return INSTR_COUNT_CALL; } - virtual bool same(const AstNode* samep) const override { - const AstNodeCCall* const asamep = static_cast(samep); - return (funcp() == asamep->funcp() && argTypes() == asamep->argTypes()); - } - AstNode* exprsp() const { return op2p(); } // op2 = expressions to print - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override; - virtual bool isOutputter() const override { return !isPure(); } - AstCFunc* funcp() const { return m_funcp; } - void funcp(AstCFunc* funcp) { m_funcp = funcp; } - void argTypes(const string& str) { m_argTypes = str; } - string argTypes() const { return m_argTypes; } - // op1p reserved for AstCMethodCall - AstNode* argsp() const { return op2p(); } - void addArgsp(AstNode* nodep) { addOp2p(nodep); } -}; - -class AstNodeFTask VL_NOT_FINAL : public AstNode { -private: - string m_name; // Name of task - string m_cname; // Name of task if DPI import - uint64_t m_dpiOpenParent = 0; // DPI import open array, if !=0, how many callees - bool m_taskPublic : 1; // Public task - bool m_attrIsolateAssign : 1; // User isolate_assignments attribute - bool m_classMethod : 1; // Class method - bool m_externProto : 1; // Extern prototype - bool m_externDef : 1; // Extern definition - bool m_prototype : 1; // Just a prototype - bool m_dpiExport : 1; // DPI exported - bool m_dpiImport : 1; // DPI imported - bool m_dpiContext : 1; // DPI import context - bool m_dpiOpenChild : 1; // DPI import open array child wrapper - bool m_dpiTask : 1; // DPI import task (vs. void function) - bool m_dpiTraceInit : 1; // DPI trace_init - bool m_isConstructor : 1; // Class constructor - bool m_isHideLocal : 1; // Verilog local - bool m_isHideProtected : 1; // Verilog protected - bool m_pure : 1; // DPI import pure (vs. virtual pure) - bool m_pureVirtual : 1; // Pure virtual - bool m_recursive : 1; // Recusive or part of recursion - bool m_underGenerate : 1; // Under generate (for warning) - bool m_virtual : 1; // Virtual method in class - VLifetime m_lifetime; // Lifetime -protected: - AstNodeFTask(VNType t, FileLine* fl, const string& name, AstNode* stmtsp) - : AstNode{t, fl} - , m_name{name} - , m_taskPublic{false} - , m_attrIsolateAssign{false} - , m_classMethod{false} - , m_externProto{false} - , m_externDef{false} - , m_prototype{false} - , m_dpiExport{false} - , m_dpiImport{false} - , m_dpiContext{false} - , m_dpiOpenChild{false} - , m_dpiTask{false} - , m_dpiTraceInit{false} - , m_isConstructor{false} - , m_isHideLocal{false} - , m_isHideProtected{false} - , m_pure{false} - , m_pureVirtual{false} - , m_recursive{false} - , m_underGenerate{false} - , m_virtual{false} { - addNOp3p(stmtsp); - cname(name); // Might be overridden by dpi import/export - } - -public: - ASTNODE_BASE_FUNCS(NodeFTask) - virtual void dump(std::ostream& str = std::cout) const override; - virtual string name() const override { return m_name; } // * = Var name - virtual bool maybePointedTo() const override { return true; } - virtual bool isGateOptimizable() const override { - return !((m_dpiExport || m_dpiImport) && !m_pure); - } - // {AstFunc only} op1 = Range output variable - virtual void name(const string& name) override { m_name = name; } - string cname() const { return m_cname; } - void cname(const string& cname) { m_cname = cname; } - // op1 = Output variable (functions only, nullptr for tasks) - AstNode* fvarp() const { return op1p(); } - void addFvarp(AstNode* nodep) { addNOp1p(nodep); } - bool isFunction() const { return fvarp() != nullptr; } - // op2 = Class/package scope - AstNode* classOrPackagep() const { return op2p(); } - void classOrPackagep(AstNode* nodep) { setNOp2p(nodep); } - // op3 = Statements/Ports/Vars - AstNode* stmtsp() const { return op3p(); } // op3 = List of statements - void addStmtsp(AstNode* nodep) { addNOp3p(nodep); } - // op4 = scope name - AstScopeName* scopeNamep() const { return VN_AS(op4p(), ScopeName); } - // MORE ACCESSORS - void dpiOpenParentInc() { ++m_dpiOpenParent; } - void dpiOpenParentClear() { m_dpiOpenParent = 0; } - uint64_t dpiOpenParent() const { return m_dpiOpenParent; } - void scopeNamep(AstNode* nodep) { setNOp4p(nodep); } - void taskPublic(bool flag) { m_taskPublic = flag; } - bool taskPublic() const { return m_taskPublic; } - void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; } - bool attrIsolateAssign() const { return m_attrIsolateAssign; } - void classMethod(bool flag) { m_classMethod = flag; } - bool classMethod() const { return m_classMethod; } - void isExternProto(bool flag) { m_externProto = flag; } - bool isExternProto() const { return m_externProto; } - void isExternDef(bool flag) { m_externDef = flag; } - bool isExternDef() const { return m_externDef; } - void prototype(bool flag) { m_prototype = flag; } - bool prototype() const { return m_prototype; } - void dpiExport(bool flag) { m_dpiExport = flag; } - bool dpiExport() const { return m_dpiExport; } - void dpiImport(bool flag) { m_dpiImport = flag; } - bool dpiImport() const { return m_dpiImport; } - void dpiContext(bool flag) { m_dpiContext = flag; } - bool dpiContext() const { return m_dpiContext; } - void dpiOpenChild(bool flag) { m_dpiOpenChild = flag; } - bool dpiOpenChild() const { return m_dpiOpenChild; } - void dpiTask(bool flag) { m_dpiTask = flag; } - bool dpiTask() const { return m_dpiTask; } - void dpiTraceInit(bool flag) { m_dpiTraceInit = flag; } - bool dpiTraceInit() const { return m_dpiTraceInit; } - void isConstructor(bool flag) { m_isConstructor = flag; } - bool isConstructor() const { return m_isConstructor; } - bool isHideLocal() const { return m_isHideLocal; } - void isHideLocal(bool flag) { m_isHideLocal = flag; } - bool isHideProtected() const { return m_isHideProtected; } - void isHideProtected(bool flag) { m_isHideProtected = flag; } - void pure(bool flag) { m_pure = flag; } - bool pure() const { return m_pure; } - void pureVirtual(bool flag) { m_pureVirtual = flag; } - bool pureVirtual() const { return m_pureVirtual; } - void recursive(bool flag) { m_recursive = flag; } - bool recursive() const { return m_recursive; } - void underGenerate(bool flag) { m_underGenerate = flag; } - bool underGenerate() const { return m_underGenerate; } - void isVirtual(bool flag) { m_virtual = flag; } - bool isVirtual() const { return m_virtual; } - void lifetime(const VLifetime& flag) { m_lifetime = flag; } - VLifetime lifetime() const { return m_lifetime; } - bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); } -}; - -class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeStmt { - // A reference to a task (or function) - // Functions are not statements, while tasks are. AstNodeStmt needs isStatement() to deal. -private: - AstNodeFTask* m_taskp = nullptr; // [AfterLink] Pointer to task referenced - AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy - string m_name; // Name of variable - string m_dotted; // Dotted part of scope the name()ed task/func is under or "" - string m_inlinedDots; // Dotted hierarchy flattened out - bool m_pli = false; // Pli system call ($name) -protected: - AstNodeFTaskRef(VNType t, FileLine* fl, bool statement, AstNode* namep, AstNode* pinsp) - : AstNodeStmt{t, fl, statement} { - setOp1p(namep); - addNOp3p(pinsp); - } - AstNodeFTaskRef(VNType t, FileLine* fl, bool statement, const string& name, AstNode* pinsp) - : AstNodeStmt{t, fl, statement} - , m_name{name} { - addNOp3p(pinsp); - } - -public: - ASTNODE_BASE_FUNCS(NodeFTaskRef) - virtual const char* broken() const override; - virtual void cloneRelink() override; - virtual void dump(std::ostream& str = std::cout) const override; - virtual string name() const override { return m_name; } // * = Var name - virtual bool isGateOptimizable() const override { - return m_taskp && m_taskp->isGateOptimizable(); - } - string dotted() const { return m_dotted; } // * = Scope name or "" - string inlinedDots() const { return m_inlinedDots; } - void inlinedDots(const string& flag) { m_inlinedDots = flag; } - AstNodeFTask* taskp() const { return m_taskp; } // [After Link] Pointer to variable - void taskp(AstNodeFTask* taskp) { m_taskp = taskp; } - virtual void name(const string& name) override { m_name = name; } - void dotted(const string& name) { m_dotted = name; } - AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } - void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } - bool pli() const { return m_pli; } - void pli(bool flag) { m_pli = flag; } - // op1 = namep - AstNode* namep() const { return op1p(); } - // op2 = reserved for AstMethodCall - // op3 = Pin interconnection list - AstNode* pinsp() const { return op3p(); } - void addPinsp(AstNode* nodep) { addOp3p(nodep); } - // op4 = scope tracking - AstScopeName* scopeNamep() const { return VN_AS(op4p(), ScopeName); } - void scopeNamep(AstNode* nodep) { setNOp4p(nodep); } -}; - -class AstNodeModule VL_NOT_FINAL : public AstNode { - // A module, package, program or interface declaration; - // something that can live directly under the TOP, - // excluding $unit package stuff -private: - string m_name; // Name of the module - const string m_origName; // Name of the module, ignoring name() changes, for dot lookup - string m_someInstanceName; // Hierarchical name of some arbitrary instance of this module. - // Used for user messages only. - bool m_modPublic : 1; // Module has public references - bool m_modTrace : 1; // Tracing this module - bool m_inLibrary : 1; // From a library, no error if not used, never top level - bool m_dead : 1; // LinkDot believes is dead; will remove in Dead visitors - bool m_hierBlock : 1; // Hiearchical Block marked by HIER_BLOCK pragma - bool m_internal : 1; // Internally created - bool m_recursive : 1; // Recursive module - bool m_recursiveClone : 1; // If recursive, what module it clones, otherwise nullptr - int m_level = 0; // 1=top module, 2=cell off top module, ... - VLifetime m_lifetime; // Lifetime - VTimescale m_timeunit; // Global time unit - VOptionBool m_unconnectedDrive; // State of `unconnected_drive -protected: - AstNodeModule(VNType t, FileLine* fl, const string& name) - : AstNode{t, fl} - , m_name{name} - , m_origName{name} - , m_modPublic{false} - , m_modTrace{false} - , m_inLibrary{false} - , m_dead{false} - , m_hierBlock{false} - , m_internal{false} - , m_recursive{false} - , m_recursiveClone{false} {} - -public: - ASTNODE_BASE_FUNCS(NodeModule) - virtual void dump(std::ostream& str) const override; - virtual bool maybePointedTo() const override { return true; } - virtual string name() const override { return m_name; } - virtual bool timescaleMatters() const = 0; - AstNode* stmtsp() const { return op2p(); } // op2 = List of statements - AstActive* activesp() const { return VN_AS(op3p(), Active); } // op3 = List of i/sblocks - // METHODS - void addInlinesp(AstNode* nodep) { addOp1p(nodep); } - void addStmtp(AstNode* nodep) { addNOp2p(nodep); } - void addActivep(AstNode* nodep) { addOp3p(nodep); } - // ACCESSORS - virtual void name(const string& name) override { m_name = name; } - virtual string origName() const override { return m_origName; } - string someInstanceName() const { return m_someInstanceName; } - void someInstanceName(const string& name) { m_someInstanceName = name; } - bool inLibrary() const { return m_inLibrary; } - void inLibrary(bool flag) { m_inLibrary = flag; } - void level(int level) { m_level = level; } - int level() const { return m_level; } - bool isTop() const { return level() == 1; } - void modPublic(bool flag) { m_modPublic = flag; } - bool modPublic() const { return m_modPublic; } - void modTrace(bool flag) { m_modTrace = flag; } - bool modTrace() const { return m_modTrace; } - void dead(bool flag) { m_dead = flag; } - bool dead() const { return m_dead; } - void hierBlock(bool flag) { m_hierBlock = flag; } - bool hierBlock() const { return m_hierBlock; } - void internal(bool flag) { m_internal = flag; } - bool internal() const { return m_internal; } - void recursive(bool flag) { m_recursive = flag; } - bool recursive() const { return m_recursive; } - void recursiveClone(bool flag) { m_recursiveClone = flag; } - bool recursiveClone() const { return m_recursiveClone; } - void lifetime(const VLifetime& flag) { m_lifetime = flag; } - VLifetime lifetime() const { return m_lifetime; } - void timeunit(const VTimescale& flag) { m_timeunit = flag; } - VTimescale timeunit() const { return m_timeunit; } - void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; } - VOptionBool unconnectedDrive() const { return m_unconnectedDrive; } -}; - -class AstNodeRange VL_NOT_FINAL : public AstNode { - // A range, sized or unsized -protected: - AstNodeRange(VNType t, FileLine* fl) - : AstNode{t, fl} {} - -public: - ASTNODE_BASE_FUNCS(NodeRange) - virtual void dump(std::ostream& str) const override; -}; - //###################################################################### // Inline VNVisitor METHODS -inline void VNVisitor::iterate(AstNode* nodep) { nodep->accept(*this); } -inline void VNVisitor::iterateNull(AstNode* nodep) { +void VNVisitor::iterate(AstNode* nodep) { nodep->accept(*this); } +void VNVisitor::iterateNull(AstNode* nodep) { if (VL_LIKELY(nodep)) nodep->accept(*this); } -inline void VNVisitor::iterateChildren(AstNode* nodep) { nodep->iterateChildren(*this); } -inline void VNVisitor::iterateChildrenBackwards(AstNode* nodep) { +void VNVisitor::iterateChildren(AstNode* nodep) { nodep->iterateChildren(*this); } +void VNVisitor::iterateChildrenBackwards(AstNode* nodep) { nodep->iterateChildrenBackwards(*this); } -inline void VNVisitor::iterateChildrenConst(AstNode* nodep) { nodep->iterateChildrenConst(*this); } -inline void VNVisitor::iterateAndNextNull(AstNode* nodep) { +void VNVisitor::iterateChildrenConst(AstNode* nodep) { nodep->iterateChildrenConst(*this); } +void VNVisitor::iterateAndNextNull(AstNode* nodep) { if (VL_LIKELY(nodep)) nodep->iterateAndNext(*this); } -inline void VNVisitor::iterateAndNextConstNullBackwards(AstNode* nodep) { +void VNVisitor::iterateAndNextConstNullBackwards(AstNode* nodep) { if (VL_LIKELY(nodep)) nodep->iterateListBackwards(*this); } -inline void VNVisitor::iterateAndNextConstNull(AstNode* nodep) { +void VNVisitor::iterateAndNextConstNull(AstNode* nodep) { if (VL_LIKELY(nodep)) nodep->iterateAndNextConst(*this); } -inline AstNode* VNVisitor::iterateSubtreeReturnEdits(AstNode* nodep) { +AstNode* VNVisitor::iterateSubtreeReturnEdits(AstNode* nodep) { return nodep->iterateSubtreeReturnEdits(*this); } -//###################################################################### +// Include macros generated by 'astgen'. These include ASTGEN_MEMBERS_ +// for each AstNode sub-type, and ASTGEN_SUPER_ for concrete final +// AstNode sub-types. The generated members include boilerplate methods related +// to cloning, visitor dispatch, and other functionality. ASTGEN_SUPER_ +// is the necessary constructor invocation for concrete AstNode sub-types +// that passes the generated type-id numbers all the way back to AstNode. +// For precise details please read the generated macros. +#include "V3Ast__gen_macros.h" -#include "V3AstNodes.h" +// AstNode subclasses +#include "V3AstNodeDType.h" +#include "V3AstNodeMath.h" +#include "V3AstNodeOther.h" + +// Inline function definitions need to go last +#include "V3AstInlines.h" #endif // Guard diff --git a/src/V3AstInlines.h b/src/V3AstInlines.h index 6d8e93b35..198ed0ec5 100644 --- a/src/V3AstInlines.h +++ b/src/V3AstInlines.h @@ -17,71 +17,175 @@ #ifndef VERILATOR_V3ASTINLINES_H_ #define VERILATOR_V3ASTINLINES_H_ -#ifndef VERILATOR_V3ASTNODES_H_ +#ifndef VERILATOR_V3AST_H_ #error "Use V3Ast.h as the include" -#include "V3AstNodes.h" // This helps code analysis tools pick up symbols in V3Ast.h and V3AstNodes.h +#include "V3Ast.h" // This helps code analysis tools pick up symbols in V3Ast.h and relaed #endif //###################################################################### -// Inline ACCESSORS +// Inline METHODS -inline int AstNode::width() const { return dtypep() ? dtypep()->width() : 0; } -inline int AstNode::widthMin() const { return dtypep() ? dtypep()->widthMin() : 0; } -inline bool AstNode::width1() const { // V3Const uses to know it can optimize +int AstNode::width() const { return dtypep() ? dtypep()->width() : 0; } +int AstNode::widthMin() const { return dtypep() ? dtypep()->widthMin() : 0; } +bool AstNode::width1() const { // V3Const uses to know it can optimize return dtypep() && dtypep()->width() == 1; } -inline int AstNode::widthInstrs() const { +int AstNode::widthInstrs() const { return (!dtypep() ? 1 : (dtypep()->isWide() ? dtypep()->widthWords() : 1)); } -inline bool AstNode::isDouble() const { +bool AstNode::isDouble() const { return dtypep() && VN_IS(dtypep(), BasicDType) && VN_AS(dtypep(), BasicDType)->isDouble(); } -inline bool AstNode::isString() const { +bool AstNode::isString() const { return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString(); } -inline bool AstNode::isSigned() const { return dtypep() && dtypep()->isSigned(); } +bool AstNode::isSigned() const { return dtypep() && dtypep()->isSigned(); } -inline bool AstNode::isZero() const { +bool AstNode::isZero() const { return (VN_IS(this, Const) && VN_AS(this, Const)->num().isEqZero()); } -inline bool AstNode::isNeqZero() const { +bool AstNode::isNeqZero() const { return (VN_IS(this, Const) && VN_AS(this, Const)->num().isNeqZero()); } -inline bool AstNode::isOne() const { - return (VN_IS(this, Const) && VN_AS(this, Const)->num().isEqOne()); -} -inline bool AstNode::isAllOnes() const { +bool AstNode::isOne() const { return (VN_IS(this, Const) && VN_AS(this, Const)->num().isEqOne()); } +bool AstNode::isAllOnes() const { return (VN_IS(this, Const) && VN_AS(this, Const)->isEqAllOnes()); } -inline bool AstNode::isAllOnesV() const { +bool AstNode::isAllOnesV() const { return (VN_IS(this, Const) && VN_AS(this, Const)->isEqAllOnesV()); } -inline bool AstNode::sameTree(const AstNode* node2p) const { +bool AstNode::sameTree(const AstNode* node2p) const { return sameTreeIter(this, node2p, true, false); } -inline bool AstNode::sameGateTree(const AstNode* node2p) const { +bool AstNode::sameGateTree(const AstNode* node2p) const { return sameTreeIter(this, node2p, true, true); } -inline void AstNodeVarRef::varp(AstVar* varp) { - m_varp = varp; +int AstNodeArrayDType::left() const { return rangep()->leftConst(); } +int AstNodeArrayDType::right() const { return rangep()->rightConst(); } +int AstNodeArrayDType::hi() const { return rangep()->hiConst(); } +int AstNodeArrayDType::lo() const { return rangep()->loConst(); } +int AstNodeArrayDType::elementsConst() const { return rangep()->elementsConst(); } +VNumRange AstNodeArrayDType::declRange() const { return VNumRange{left(), right()}; } + +AstRange::AstRange(FileLine* fl, int left, int right) + : ASTGEN_SUPER_Range(fl) { + leftp(new AstConst{fl, static_cast(left)}); + rightp(new AstConst{fl, static_cast(right)}); +} +AstRange::AstRange(FileLine* fl, const VNumRange& range) + : ASTGEN_SUPER_Range(fl) { + leftp(new AstConst{fl, static_cast(range.left())}); + rightp(new AstConst{fl, static_cast(range.right())}); +} +int AstRange::leftConst() const { + AstConst* const constp = VN_CAST(leftp(), Const); + return (constp ? constp->toSInt() : 0); +} +int AstRange::rightConst() const { + AstConst* const constp = VN_CAST(rightp(), Const); + return (constp ? constp->toSInt() : 0); +} + +int AstQueueDType::boundConst() const { + AstConst* const constp = VN_CAST(boundp(), Const); + return (constp ? constp->toSInt() : 0); +} + +AstPin::AstPin(FileLine* fl, int pinNum, AstVarRef* varname, AstNode* exprp) + : ASTGEN_SUPER_Pin(fl) + , m_pinNum{pinNum} + , m_name{varname->name()} { + this->exprp(exprp); +} + +AstDpiExportUpdated::AstDpiExportUpdated(FileLine* fl, AstVarScope* varScopep) + : ASTGEN_SUPER_DpiExportUpdated(fl) { + this->varRefp(new AstVarRef{fl, varScopep, VAccess::WRITE}); +} + +AstVarScope* AstDpiExportUpdated::varScopep() const { return varRefp()->varScopep(); } + +AstPackArrayDType::AstPackArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, + AstRange* rangep) + : ASTGEN_SUPER_PackArrayDType(fl) { + childDTypep(dtp); // Only for parser + refDTypep(nullptr); + this->rangep(rangep); + dtypep(nullptr); // V3Width will resolve + const int width = subDTypep()->width() * rangep->elementsConst(); + widthForce(width, width); +} +AstPackArrayDType::AstPackArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep) + : ASTGEN_SUPER_PackArrayDType(fl) { + refDTypep(dtp); + this->rangep(rangep); + dtypep(this); + const int width = subDTypep()->width() * rangep->elementsConst(); + widthForce(width, width); +} + +int AstBasicDType::hi() const { return (rangep() ? rangep()->hiConst() : m.m_nrange.hi()); } +int AstBasicDType::lo() const { return (rangep() ? rangep()->loConst() : m.m_nrange.lo()); } +int AstBasicDType::elements() const { + return (rangep() ? rangep()->elementsConst() : m.m_nrange.elements()); +} +bool AstBasicDType::littleEndian() const { + return (rangep() ? rangep()->littleEndian() : m.m_nrange.littleEndian()); +} + +bool AstActive::hasInitial() const { return m_sensesp->hasInitial(); } +bool AstActive::hasSettle() const { return m_sensesp->hasSettle(); } +bool AstActive::hasClocked() const { return m_sensesp->hasClocked(); } + +AstElabDisplay::AstElabDisplay(FileLine* fl, VDisplayType dispType, AstNode* exprsp) + : ASTGEN_SUPER_ElabDisplay(fl) { + addFmtp(new AstSFormatF{fl, AstSFormatF::NoFormat(), exprsp}); + m_displayType = dispType; +} + +AstCStmt::AstCStmt(FileLine* fl, const string& textStmt) + : ASTGEN_SUPER_CStmt(fl) { + addExprsp(new AstText{fl, textStmt, true}); +} + +AstCMath::AstCMath(FileLine* fl, const string& textStmt, int setwidth, bool cleanOut) + : ASTGEN_SUPER_CMath(fl) + , m_cleanOut{cleanOut} + , m_pure{true} { + addExprsp(new AstText{fl, textStmt, true}); + if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); +} + +AstVarRef::AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access) + : ASTGEN_SUPER_VarRef(fl, varp->name(), varp, access) {} +// This form only allowed post-link (see above) +AstVarRef::AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access) + : ASTGEN_SUPER_VarRef(fl, varscp->varp()->name(), varscp->varp(), access) { + varScopep(varscp); +} +bool AstVarRef::same(const AstVarRef* samep) const { + if (varScopep()) { + return (varScopep() == samep->varScopep() && access() == samep->access()); + } else { + return (selfPointer() == samep->selfPointer() && varp()->name() == samep->varp()->name() + && access() == samep->access()); + } +} +bool AstVarRef::sameNoLvalue(AstVarRef* samep) const { + if (varScopep()) { + return (varScopep() == samep->varScopep()); + } else { + return (selfPointer() == samep->selfPointer() + && (!selfPointer().empty() || !samep->selfPointer().empty()) + && varp()->name() == samep->varp()->name()); + } +} + +AstVarXRef::AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const VAccess& access) + : ASTGEN_SUPER_VarXRef(fl, varp->name(), varp, access) + , m_dotted{dotted} { dtypeFrom(varp); } -inline bool AstNodeDType::isFourstate() const { return basicp()->isFourstate(); } - -inline void AstNodeArrayDType::rangep(AstRange* nodep) { setOp2p(nodep); } -inline int AstNodeArrayDType::left() const { return rangep()->leftConst(); } -inline int AstNodeArrayDType::right() const { return rangep()->rightConst(); } -inline int AstNodeArrayDType::hi() const { return rangep()->hiConst(); } -inline int AstNodeArrayDType::lo() const { return rangep()->loConst(); } -inline int AstNodeArrayDType::elementsConst() const { return rangep()->elementsConst(); } -inline VNumRange AstNodeArrayDType::declRange() const { return VNumRange{left(), right()}; } - -inline void AstIfaceRefDType::cloneRelink() { - if (m_cellp && m_cellp->clonep()) m_cellp = m_cellp->clonep(); - if (m_ifacep && m_ifacep->clonep()) m_ifacep = m_ifacep->clonep(); - if (m_modportp && m_modportp->clonep()) m_modportp = m_modportp->clonep(); -} - #endif // Guard diff --git a/src/V3AstNodeDType.h b/src/V3AstNodeDType.h new file mode 100644 index 000000000..4da216427 --- /dev/null +++ b/src/V3AstNodeDType.h @@ -0,0 +1,1256 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: AstNode sub-types representing data types +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2022 by Wilson Snyder. This program is free software; you +// can redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* +// +// This files contains all 'AstNode' sub-types that relate to the +// representation of data types. +// +//************************************************************************* + +#ifndef VERILATOR_V3ASTNODEDTYPE_H_ +#define VERILATOR_V3ASTNODEDTYPE_H_ + +#ifndef VERILATOR_V3AST_H_ +#error "Use V3Ast.h as the include" +#include "V3Ast.h" // This helps code analysis tools pick up symbols in V3Ast.h +#define VL_NOT_FINAL // This #define fixes broken code folding in the CLion IDE +#endif + +// === Abstract base node types (AstNode*) ===================================== + +class AstNodeDType VL_NOT_FINAL : public AstNode { + // Ideally width() would migrate to BasicDType as that's where it makes sense, + // but it's currently so prevalent in the code we leave it here. + // Note the below members are included in AstTypeTable::Key lookups +private: + int m_width = 0; // (also in AstTypeTable::Key) Bit width of operation + int m_widthMin + = 0; // (also in AstTypeTable::Key) If unsized, bitwidth of minimum implementation + VSigning m_numeric; // (also in AstTypeTable::Key) Node is signed + // Other members + bool m_generic = false; // Simple globally referenced type, don't garbage collect + // Unique number assigned to each dtype during creation for IEEE matching + static int s_uniqueNum; + +protected: + // CONSTRUCTORS + AstNodeDType(VNType t, FileLine* fl) + : AstNode{t, fl} {} + +public: + ASTGEN_MEMBERS_NodeDType; + // ACCESSORS + void dump(std::ostream& str) const override; + virtual void dumpSmall(std::ostream& str) const; + bool hasDType() const override { return true; } + /// Require VlUnpacked, instead of [] for POD elements. + /// A non-POD object is always compound, but some POD elements + /// are compound when methods calls operate on object, or when + /// under another compound-requiring object e.g. class + virtual bool isCompound() const = 0; + // (Slow) recurse down to find basic data type + virtual AstBasicDType* basicp() const = 0; + // recurses over typedefs/const/enum to next non-typeref type + virtual AstNodeDType* skipRefp() const = 0; + // recurses over typedefs to next non-typeref-or-const type + virtual AstNodeDType* skipRefToConstp() const = 0; + // recurses over typedefs/const to next non-typeref-or-enum/struct type + virtual AstNodeDType* skipRefToEnump() const = 0; + // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) + virtual int widthAlignBytes() const = 0; + // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... + virtual int widthTotalBytes() const = 0; + bool maybePointedTo() const override { return true; } + // Iff has a non-null refDTypep(), as generic node function + virtual AstNodeDType* virtRefDTypep() const { return nullptr; } + // Iff has refDTypep(), set as generic node function + virtual void virtRefDTypep(AstNodeDType* nodep) {} + // Iff has a non-null second dtypep, as generic node function + virtual AstNodeDType* virtRefDType2p() const { return nullptr; } + // Iff has second dtype, set as generic node function + virtual void virtRefDType2p(AstNodeDType* nodep) {} + // Assignable equivalence. Call skipRefp() on this and samep before calling + virtual bool similarDType(AstNodeDType* samep) const = 0; + // Iff has a non-null subDTypep(), as generic node function + virtual AstNodeDType* subDTypep() const { return nullptr; } + virtual bool isFourstate() const; + // Ideally an IEEE $typename + virtual string prettyDTypeName() const { return prettyTypeName(); } + string prettyDTypeNameQ() const { return "'" + prettyDTypeName() + "'"; } + // + // Changing the width may confuse the data type resolution, so must clear + // TypeTable cache after use. + void widthForce(int width, int widthMin) { + m_width = width; + m_widthMin = widthMin; + } + // For backward compatibility inherit width and signing from the subDType/base type + void widthFromSub(AstNodeDType* nodep) { + m_width = nodep->m_width; + m_widthMin = nodep->m_widthMin; + m_numeric = nodep->m_numeric; + } + // + int width() const { return m_width; } + void numeric(VSigning flag) { m_numeric = flag; } + bool isSigned() const { return m_numeric.isSigned(); } + bool isNosign() const { return m_numeric.isNosign(); } + VSigning numeric() const { return m_numeric; } + int widthWords() const { return VL_WORDS_I(width()); } + int widthMin() const { // If sized, the size, if unsized the min digits to represent it + return m_widthMin ? m_widthMin : m_width; + } + int widthPow2() const; + void widthMinFromWidth() { m_widthMin = m_width; } + bool widthSized() const { return !m_widthMin || m_widthMin == m_width; } + bool generic() const { return m_generic; } + void generic(bool flag) { m_generic = flag; } + std::pair dimensions(bool includeBasic); + uint32_t arrayUnpackedElements(); // 1, or total multiplication of all dimensions + static int uniqueNumInc() { return ++s_uniqueNum; } + const char* charIQWN() const { + return (isString() ? "N" : isWide() ? "W" : isQuad() ? "Q" : "I"); + } + string cType(const string& name, bool forFunc, bool isRef) const; + bool isLiteralType() const; // Does this represent a C++ LiteralType? (can be constexpr) + +private: + class CTypeRecursed; + CTypeRecursed cTypeRecurse(bool compound) const; +}; +class AstNodeArrayDType VL_NOT_FINAL : public AstNodeDType { + // Array data type, ie "some_dtype var_name [2:0]" + // @astgen op1 := childDTypep : Optional[AstNodeDType] // moved to refDTypep() in V3Width + // @astgen op2 := rangep : Optional[AstRange] // array bounds +private: + AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing) + + AstNode* rangenp() const { return reinterpret_cast(rangep()); } + +protected: + AstNodeArrayDType(VNType t, FileLine* fl) + : AstNodeDType{t, fl} {} + +public: + ASTGEN_MEMBERS_NodeArrayDType; + void dump(std::ostream& str) const override; + void dumpSmall(std::ostream& str) const override; + const char* broken() const override { + BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) + || (!m_refDTypep && childDTypep()))); + return nullptr; + } + void cloneRelink() override { + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); + } + bool same(const AstNode* samep) const override { + const AstNodeArrayDType* const asamep = static_cast(samep); + return (hi() == asamep->hi() && subDTypep() == asamep->subDTypep() + && rangenp()->sameTree(asamep->rangenp())); + } // HashedDT doesn't recurse, so need to check children + bool similarDType(AstNodeDType* samep) const override { + const AstNodeArrayDType* const asamep = static_cast(samep); + return (asamep && type() == samep->type() && hi() == asamep->hi() + && rangenp()->sameTree(asamep->rangenp()) + && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); + } + AstNodeDType* getChildDTypep() const override { return childDTypep(); } + AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } + void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } + // METHODS + AstBasicDType* basicp() const override { + return subDTypep()->basicp(); + } // (Slow) recurse down to find basic data type + AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } + int widthTotalBytes() const override { + return elementsConst() * subDTypep()->widthTotalBytes(); + } + inline int left() const; + inline int right() const; + inline int hi() const; + inline int lo() const; + inline int elementsConst() const; + inline VNumRange declRange() const; +}; +class AstNodeUOrStructDType VL_NOT_FINAL : public AstNodeDType { + // A struct or union; common handling + // @astgen op1 := membersp : List[AstMemberDType] +private: + // TYPES + using MemberNameMap = std::map; + // MEMBERS + string m_name; // Name from upper typedef, if any + bool m_packed; + bool m_isFourstate = false; // V3Width computes + MemberNameMap m_members; + const int m_uniqueNum; + +protected: + AstNodeUOrStructDType(VNType t, FileLine* fl, VSigning numericUnpack) + : AstNodeDType{t, fl} + , m_uniqueNum{uniqueNumInc()} { + // VSigning::NOSIGN overloaded to indicate not packed + m_packed = (numericUnpack != VSigning::NOSIGN); + numeric(VSigning::fromBool(numericUnpack.isSigned())); + } + +public: + ASTGEN_MEMBERS_NodeUOrStructDType; + int uniqueNum() const { return m_uniqueNum; } + const char* broken() const override; + void dump(std::ostream& str) const override; + bool isCompound() const override { return false; } // Because don't support unpacked + // For basicp() we reuse the size to indicate a "fake" basic type of same size + AstBasicDType* basicp() const override { + return (isFourstate() + ? VN_AS(findLogicRangeDType(VNumRange{width() - 1, 0}, width(), numeric()), + BasicDType) + : VN_AS(findBitRangeDType(VNumRange{width() - 1, 0}, width(), numeric()), + BasicDType)); + } + AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) + int widthAlignBytes() const override; + // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... + int widthTotalBytes() const override; + bool similarDType(AstNodeDType* samep) const override { + return this == samep; // We don't compare members, require exact equivalence + } + string name() const override { return m_name; } + void name(const string& flag) override { m_name = flag; } + bool packed() const { return m_packed; } + // packed() but as don't support unpacked, presently all structs + static bool packedUnsup() { return true; } + void isFourstate(bool flag) { m_isFourstate = flag; } + bool isFourstate() const override { return m_isFourstate; } + void clearCache() { m_members.clear(); } + void repairMemberCache(); + AstMemberDType* findMember(const string& name) const { + const auto it = m_members.find(name); + return (it == m_members.end()) ? nullptr : it->second; + } + static int lo() { return 0; } + int hi() const { return dtypep()->width() - 1; } // Packed classes look like arrays + VNumRange declRange() const { return VNumRange{hi(), lo()}; } +}; + +// === Concrete node types ===================================================== + +// === AstNode === +class AstEnumItem final : public AstNode { + // @astgen op1 := rangep : Optional[AstRange] // Range for name appending + // @astgen op2 := valuep : Optional[AstNode] +private: + string m_name; + +public: + // Parents: ENUM + AstEnumItem(FileLine* fl, const string& name, AstRange* rangep, AstNode* valuep) + : ASTGEN_SUPER_EnumItem(fl) + , m_name{name} { + this->rangep(rangep); + this->valuep(valuep); + } + ASTGEN_MEMBERS_EnumItem; + string name() const override { return m_name; } + bool maybePointedTo() const override { return true; } + bool hasDType() const override { return true; } + void name(const string& flag) override { m_name = flag; } +}; + +// === AstNodeDType === +class AstAssocArrayDType final : public AstNodeDType { + // Associative array data type, ie "[some_dtype]" + // @astgen op1 := childDTypep : Optional[AstNodeDType] // moved to refDTypep() in V3Width + // @astgen op2 := keyChildDTypep : Optional[AstNodeDType] +private: + AstNodeDType* m_refDTypep; // Elements of this type (after widthing) + AstNodeDType* m_keyDTypep; // Keys of this type (after widthing) +public: + AstAssocArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNodeDType* keyDtp) + : ASTGEN_SUPER_AssocArrayDType(fl) { + childDTypep(dtp); // Only for parser + keyChildDTypep(keyDtp); // Only for parser + refDTypep(nullptr); + keyDTypep(nullptr); + dtypep(nullptr); // V3Width will resolve + } + AstAssocArrayDType(FileLine* fl, AstNodeDType* dtp, AstNodeDType* keyDtp) + : ASTGEN_SUPER_AssocArrayDType(fl) { + refDTypep(dtp); + keyDTypep(keyDtp); + dtypep(dtp); + } + ASTGEN_MEMBERS_AssocArrayDType; + const char* broken() const override { + BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) + || (!m_refDTypep && childDTypep()))); + BROKEN_RTN(!((m_keyDTypep && !childDTypep() && m_keyDTypep->brokeExists()) + || (!m_keyDTypep && childDTypep()))); + return nullptr; + } + void cloneRelink() override { + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); + if (m_keyDTypep && m_keyDTypep->clonep()) m_keyDTypep = m_keyDTypep->clonep(); + } + bool same(const AstNode* samep) const override { + const AstAssocArrayDType* const asamep = static_cast(samep); + if (!asamep->subDTypep()) return false; + if (!asamep->keyDTypep()) return false; + return (subDTypep() == asamep->subDTypep() && keyDTypep() == asamep->keyDTypep()); + } + bool similarDType(AstNodeDType* samep) const override { + const AstAssocArrayDType* const asamep = static_cast(samep); + return type() == samep->type() && asamep->subDTypep() + && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); + } + string prettyDTypeName() const override; + void dumpSmall(std::ostream& str) const override; + AstNodeDType* getChildDTypep() const override { return childDTypep(); } + AstNodeDType* getChild2DTypep() const override { return keyChildDTypep(); } + AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } + void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } + AstNodeDType* virtRefDType2p() const override { return m_keyDTypep; } + void virtRefDType2p(AstNodeDType* nodep) override { keyDTypep(nodep); } + // + AstNodeDType* keyDTypep() const { return m_keyDTypep ? m_keyDTypep : keyChildDTypep(); } + void keyDTypep(AstNodeDType* nodep) { m_keyDTypep = nodep; } + // METHODS + AstBasicDType* basicp() const override { return nullptr; } + AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } + int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } + bool isCompound() const override { return true; } +}; +class AstBasicDType final : public AstNodeDType { + // Builtin atomic/vectored data type + // @astgen op1 := rangep : Optional[AstRange] // Range of variable +private: + struct Members { + VBasicDTypeKwd m_keyword; // (also in VBasicTypeKey) What keyword created basic type + VNumRange m_nrange; // (also in VBasicTypeKey) Numeric msb/lsb (if non-opaque keyword) + bool operator==(const Members& rhs) const { + return rhs.m_keyword == m_keyword && rhs.m_nrange == m_nrange; + } + } m; + // See also in AstNodeDType: m_width, m_widthMin, m_numeric(issigned) +public: + AstBasicDType(FileLine* fl, VBasicDTypeKwd kwd, const VSigning& signst = VSigning::NOSIGN) + : ASTGEN_SUPER_BasicDType(fl) { + init(kwd, signst, 0, -1, nullptr); + } + AstBasicDType(FileLine* fl, VFlagLogicPacked, int wantwidth) + : ASTGEN_SUPER_BasicDType(fl) { + init(VBasicDTypeKwd::LOGIC, VSigning::NOSIGN, wantwidth, -1, nullptr); + } + AstBasicDType(FileLine* fl, VFlagBitPacked, int wantwidth) + : ASTGEN_SUPER_BasicDType(fl) { + init(VBasicDTypeKwd::BIT, VSigning::NOSIGN, wantwidth, -1, nullptr); + } + AstBasicDType(FileLine* fl, VBasicDTypeKwd kwd, VSigning numer, int wantwidth, int widthmin) + : ASTGEN_SUPER_BasicDType(fl) { + init(kwd, numer, wantwidth, widthmin, nullptr); + } + AstBasicDType(FileLine* fl, VBasicDTypeKwd kwd, VSigning numer, VNumRange range, int widthmin) + : ASTGEN_SUPER_BasicDType(fl) { + init(kwd, numer, range.elements(), widthmin, nullptr); + m.m_nrange = range; // as init() presumes lsb==0, but range.lsb() might not be + } + // See also addRange in verilog.y +private: + void init(VBasicDTypeKwd kwd, VSigning numer, int wantwidth, int wantwidthmin, + AstRange* rangep); + +public: + ASTGEN_MEMBERS_BasicDType; + void dump(std::ostream& str) const override; + // width/widthMin/numeric compared elsewhere + bool same(const AstNode* samep) const override { + const AstBasicDType* const sp = static_cast(samep); + return m == sp->m; + } + bool similarDType(AstNodeDType* samep) const override { + return type() == samep->type() && same(samep); + } + string name() const override { return m.m_keyword.ascii(); } + string prettyDTypeName() const override; + const char* broken() const override { + BROKEN_RTN(dtypep() != this); + return nullptr; + } + void setSignedState(const VSigning& signst) { + // Note NOSIGN does NOT change the state; this is required by the parser + if (signst == VSigning::UNSIGNED) { + numeric(signst); + } else if (signst == VSigning::SIGNED) { + numeric(signst); + } + } + // METHODS + AstBasicDType* basicp() const override { return (AstBasicDType*)this; } + AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) + int widthAlignBytes() const override; + // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... + int widthTotalBytes() const override; + bool isFourstate() const override { return keyword().isFourstate(); } + VBasicDTypeKwd keyword() const { // Avoid using - use isSomething accessors instead + return m.m_keyword; + } + bool isBitLogic() const { return keyword().isBitLogic(); } + bool isDouble() const { return keyword().isDouble(); } + bool isEventValue() const { return keyword().isEventValue(); } + bool isOpaque() const { return keyword().isOpaque(); } + bool isString() const { return keyword().isString(); } + bool isZeroInit() const { return keyword().isZeroInit(); } + bool isRanged() const { return rangep() || m.m_nrange.ranged(); } + bool isDpiBitVec() const { // DPI uses svBitVecVal + return keyword() == VBasicDTypeKwd::BIT && isRanged(); + } + bool isDpiLogicVec() const { // DPI uses svLogicVecVal + return keyword().isFourstate() && !(keyword() == VBasicDTypeKwd::LOGIC && !isRanged()); + } + bool isDpiPrimitive() const { // DPI uses a primitive type + return !isDpiBitVec() && !isDpiLogicVec(); + } + // Generally the lo/hi/left/right funcs should be used instead of nrange() + const VNumRange& nrange() const { return m.m_nrange; } + inline int hi() const; + inline int lo() const; + inline int elements() const; + int left() const { return littleEndian() ? lo() : hi(); } // How to show a declaration + int right() const { return littleEndian() ? hi() : lo(); } + inline bool littleEndian() const; + bool implicit() const { return keyword() == VBasicDTypeKwd::LOGIC_IMPLICIT; } + VNumRange declRange() const { return isRanged() ? VNumRange{left(), right()} : VNumRange{}; } + void cvtRangeConst(); // Convert to smaller representation + bool isCompound() const override { return isString(); } +}; +class AstBracketArrayDType final : public AstNodeDType { + // Associative/Queue/Normal array data type, ie "[dtype_or_expr]" + // only for early parsing then becomes another data type + // @astgen op1 := childDTypep : Optional[AstNodeDType] // moved to refDTypep() in V3Width + // @astgen op2 := elementsp : AstNode // ??? key dtype ??? +public: + AstBracketArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* childDTypep, + AstNode* elementsp) + : ASTGEN_SUPER_BracketArrayDType(fl) { + this->childDTypep(childDTypep); + this->elementsp(elementsp); + } + ASTGEN_MEMBERS_BracketArrayDType; + bool similarDType(AstNodeDType* samep) const override { V3ERROR_NA_RETURN(false); } + AstNodeDType* subDTypep() const override { return childDTypep(); } + // METHODS + // Will be removed in V3Width, which relies on this + // being a child not a dtype pointed node + bool maybePointedTo() const override { return false; } + AstBasicDType* basicp() const override { return nullptr; } + AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + int widthAlignBytes() const override { V3ERROR_NA_RETURN(0); } + int widthTotalBytes() const override { V3ERROR_NA_RETURN(0); } + bool isCompound() const override { return true; } +}; +class AstClassRefDType final : public AstNodeDType { + // Reference to a class + // @astgen op1 := paramsp: List[AstPin] +private: + AstClass* m_classp; // data type pointed to, BELOW the AstTypedef + AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy +public: + AstClassRefDType(FileLine* fl, AstClass* classp, AstPin* paramsp) + : ASTGEN_SUPER_ClassRefDType(fl) + , m_classp{classp} { + this->dtypep(this); + this->addParamsp(paramsp); + } + ASTGEN_MEMBERS_ClassRefDType; + // METHODS + const char* broken() const override; + void cloneRelink() override; + bool same(const AstNode* samep) const override { + const AstClassRefDType* const asamep = static_cast(samep); + return (m_classp == asamep->m_classp && m_classOrPackagep == asamep->m_classOrPackagep); + } + bool similarDType(AstNodeDType* samep) const override { + return this == samep || (type() == samep->type() && same(samep)); + } + void dump(std::ostream& str = std::cout) const override; + void dumpSmall(std::ostream& str) const override; + string name() const override; + AstBasicDType* basicp() const override { return nullptr; } + AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + int widthAlignBytes() const override { return 0; } + int widthTotalBytes() const override { return 0; } + AstNodeDType* virtRefDTypep() const override { return nullptr; } + void virtRefDTypep(AstNodeDType* nodep) override {} + AstNodeDType* subDTypep() const override { return nullptr; } + AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } + void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } + AstClass* classp() const { return m_classp; } + void classp(AstClass* nodep) { m_classp = nodep; } + bool isCompound() const override { return true; } +}; +class AstConstDType final : public AstNodeDType { + // const data type, ie "const some_dtype var_name [2:0]" + // ConstDType are removed in V3LinkLValue and become AstVar::isConst. + // When more generic types are supported AstConstDType will be propagated further. + // @astgen op1 := childDTypep : Optional[AstNodeDType] +private: + AstNodeDType* m_refDTypep = nullptr; // Inherit from this base data type +public: + AstConstDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) + : ASTGEN_SUPER_ConstDType(fl) { + childDTypep(dtp); // Only for parser + refDTypep(nullptr); // V3Width will resolve + dtypep(nullptr); // V3Width will resolve + widthFromSub(subDTypep()); + } + ASTGEN_MEMBERS_ConstDType; + const char* broken() const override { + BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) + || (!m_refDTypep && childDTypep()))); + return nullptr; + } + void cloneRelink() override { + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); + } + bool same(const AstNode* samep) const override { + const AstConstDType* const sp = static_cast(samep); + return (m_refDTypep == sp->m_refDTypep); + } + bool similarDType(AstNodeDType* samep) const override { + return skipRefp()->similarDType(samep->skipRefp()); + } + AstNodeDType* getChildDTypep() const override { return childDTypep(); } + AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } + void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } + // METHODS + AstBasicDType* basicp() const override { return subDTypep()->basicp(); } + AstNodeDType* skipRefp() const override { return subDTypep()->skipRefp(); } + AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); } + int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } + int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } + bool isCompound() const override { + v3fatalSrc("call isCompound on subdata type, not reference"); + return false; + } +}; +class AstDefImplicitDType final : public AstNodeDType { + // For parsing enum/struct/unions that are declared with a variable rather than typedef + // This allows "var enum {...} a,b" to share the enum definition for both variables + // After link, these become typedefs + // @astgen op1 := childDTypep : Optional[AstNodeDType] +private: + string m_name; + void* m_containerp; // In what scope is the name unique, so we can know what are duplicate + // definitions (arbitrary value) + const int m_uniqueNum; + +public: + AstDefImplicitDType(FileLine* fl, const string& name, void* containerp, VFlagChildDType, + AstNodeDType* dtp) + : ASTGEN_SUPER_DefImplicitDType(fl) + , m_name{name} + , m_containerp{containerp} + , m_uniqueNum{uniqueNumInc()} { + childDTypep(dtp); // Only for parser + dtypep(nullptr); // V3Width will resolve + } + ASTGEN_MEMBERS_DefImplicitDType; + int uniqueNum() const { return m_uniqueNum; } + bool same(const AstNode* samep) const override { + const AstDefImplicitDType* const sp = static_cast(samep); + return uniqueNum() == sp->uniqueNum(); + } + bool similarDType(AstNodeDType* samep) const override { + return type() == samep->type() && same(samep); + } + AstNodeDType* getChildDTypep() const override { return childDTypep(); } + AstNodeDType* subDTypep() const override { return dtypep() ? dtypep() : childDTypep(); } + void* containerp() const { return m_containerp; } + // METHODS + // op1 = Range of variable + AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } + AstBasicDType* basicp() const override { return subDTypep()->basicp(); } + AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + int widthAlignBytes() const override { return dtypep()->widthAlignBytes(); } + int widthTotalBytes() const override { return dtypep()->widthTotalBytes(); } + string name() const override { return m_name; } + void name(const string& flag) override { m_name = flag; } + bool isCompound() const override { return false; } +}; +class AstDynArrayDType final : public AstNodeDType { + // Dynamic array data type, ie "[]" + // @astgen op1 := childDTypep : Optional[AstNodeDType] // moved to refDTypep() in V3Width +private: + AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing) +public: + AstDynArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) + : ASTGEN_SUPER_DynArrayDType(fl) { + childDTypep(dtp); // Only for parser + refDTypep(nullptr); + dtypep(nullptr); // V3Width will resolve + } + AstDynArrayDType(FileLine* fl, AstNodeDType* dtp) + : ASTGEN_SUPER_DynArrayDType(fl) { + refDTypep(dtp); + dtypep(nullptr); // V3Width will resolve + } + ASTGEN_MEMBERS_DynArrayDType; + const char* broken() const override { + BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) + || (!m_refDTypep && childDTypep()))); + return nullptr; + } + void cloneRelink() override { + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); + } + bool same(const AstNode* samep) const override { + const AstAssocArrayDType* const asamep = static_cast(samep); + if (!asamep->subDTypep()) return false; + return subDTypep() == asamep->subDTypep(); + } + bool similarDType(AstNodeDType* samep) const override { + const AstAssocArrayDType* const asamep = static_cast(samep); + return type() == samep->type() && asamep->subDTypep() + && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); + } + string prettyDTypeName() const override; + void dumpSmall(std::ostream& str) const override; + AstNodeDType* getChildDTypep() const override { return childDTypep(); } + AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } + void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } + // METHODS + AstBasicDType* basicp() const override { return nullptr; } + AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } + int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } + bool isCompound() const override { return true; } +}; +class AstEmptyQueueDType final : public AstNodeDType { + // For EmptyQueue +public: + explicit AstEmptyQueueDType(FileLine* fl) + : ASTGEN_SUPER_EmptyQueueDType(fl) { + dtypep(this); + } + ASTGEN_MEMBERS_EmptyQueueDType; + void dumpSmall(std::ostream& str) const override; + bool hasDType() const override { return true; } + bool maybePointedTo() const override { return true; } + bool undead() const override { return true; } + AstNodeDType* subDTypep() const override { return nullptr; } + AstNodeDType* virtRefDTypep() const override { return nullptr; } + void virtRefDTypep(AstNodeDType* nodep) override {} + bool similarDType(AstNodeDType* samep) const override { return this == samep; } + AstBasicDType* basicp() const override { return nullptr; } + // cppcheck-suppress csyleCast + AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + // cppcheck-suppress csyleCast + AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + // cppcheck-suppress csyleCast + AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + int widthAlignBytes() const override { return 1; } + int widthTotalBytes() const override { return 1; } + bool isCompound() const override { return false; } +}; +class AstEnumDType final : public AstNodeDType { + // Parents: TYPEDEF/MODULE + // @astgen op1 := childDTypep : Optional[AstNodeDType] + // @astgen op2 := itemsp : List[AstEnumItem] +private: + string m_name; // Name from upper typedef, if any + AstNodeDType* m_refDTypep = nullptr; // Elements are of this type after V3Width + const int m_uniqueNum = 0; + +public: + AstEnumDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstEnumItem* itemsp) + : ASTGEN_SUPER_EnumDType(fl) + , m_uniqueNum{uniqueNumInc()} { + childDTypep(dtp); // Only for parser + refDTypep(nullptr); + addItemsp(itemsp); + dtypep(nullptr); // V3Width will resolve + widthFromSub(subDTypep()); + } + ASTGEN_MEMBERS_EnumDType; + const char* broken() const override { + BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) + || (!m_refDTypep && childDTypep()))); + return nullptr; + } + void cloneRelink() override { + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); + } + int uniqueNum() const { return m_uniqueNum; } + bool same(const AstNode* samep) const override { + const AstEnumDType* const sp = static_cast(samep); + return uniqueNum() == sp->uniqueNum(); + } + bool similarDType(AstNodeDType* samep) const override { return this == samep; } + AstNodeDType* getChildDTypep() const override { return childDTypep(); } + AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } + void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } + string name() const override { return m_name; } + void name(const string& flag) override { m_name = flag; } + // METHODS + AstBasicDType* basicp() const override { return subDTypep()->basicp(); } + AstNodeDType* skipRefp() const override { return subDTypep()->skipRefp(); } + AstNodeDType* skipRefToConstp() const override { return subDTypep()->skipRefToConstp(); } + // cppcheck-suppress csyleCast + AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } + int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } + int itemCount() const { + size_t count = 0; + for (AstNode* itemp = itemsp(); itemp; itemp = itemp->nextp()) count++; + return count; + } + bool isCompound() const override { return false; } +}; +class AstIfaceRefDType final : public AstNodeDType { + // Reference to an interface, either for a port, or inside parent cell +private: + FileLine* m_modportFileline; // Where modport token was + string m_cellName; // "" = no cell, such as when connects to 'input' iface + string m_ifaceName; // Interface name + string m_modportName; // "" = no modport + AstIface* m_ifacep = nullptr; // Pointer to interface; note cellp() should override + AstCell* m_cellp = nullptr; // When exact parent cell known; not a guess + AstModport* m_modportp = nullptr; // nullptr = unlinked or no modport +public: + AstIfaceRefDType(FileLine* fl, const string& cellName, const string& ifaceName) + : ASTGEN_SUPER_IfaceRefDType(fl) + , m_modportFileline{nullptr} + , m_cellName{cellName} + , m_ifaceName{ifaceName} + , m_modportName{""} {} + AstIfaceRefDType(FileLine* fl, FileLine* modportFl, const string& cellName, + const string& ifaceName, const string& modport) + : ASTGEN_SUPER_IfaceRefDType(fl) + , m_modportFileline{modportFl} + , m_cellName{cellName} + , m_ifaceName{ifaceName} + , m_modportName{modport} {} + ASTGEN_MEMBERS_IfaceRefDType; + // METHODS + const char* broken() const override; + void dump(std::ostream& str = std::cout) const override; + void dumpSmall(std::ostream& str) const override; + void cloneRelink() override; + AstBasicDType* basicp() const override { return nullptr; } + AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + bool similarDType(AstNodeDType* samep) const override { return this == samep; } + int widthAlignBytes() const override { return 1; } + int widthTotalBytes() const override { return 1; } + FileLine* modportFileline() const { return m_modportFileline; } + string cellName() const { return m_cellName; } + void cellName(const string& name) { m_cellName = name; } + string ifaceName() const { return m_ifaceName; } + void ifaceName(const string& name) { m_ifaceName = name; } + string modportName() const { return m_modportName; } + AstIface* ifaceViaCellp() const; // Use cellp or ifacep + AstIface* ifacep() const { return m_ifacep; } + void ifacep(AstIface* nodep) { m_ifacep = nodep; } + AstCell* cellp() const { return m_cellp; } + void cellp(AstCell* nodep) { m_cellp = nodep; } + AstModport* modportp() const { return m_modportp; } + void modportp(AstModport* modportp) { m_modportp = modportp; } + bool isModport() { return !m_modportName.empty(); } + bool isCompound() const override { return true; } // But not relevant +}; +class AstMemberDType final : public AstNodeDType { + // A member of a struct/union + // PARENT: AstNodeUOrStructDType + // @astgen op1 := childDTypep : Optional[AstNodeDType] +private: + AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing) + string m_name; // Name of variable + string m_tag; // Holds the string of the verilator tag -- used in XML output. + int m_lsb = -1; // Within this level's packed struct, the LSB of the first bit of the member + // UNSUP: int m_randType; // Randomization type (IEEE) +public: + AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp) + : ASTGEN_SUPER_MemberDType(fl) + , m_name{name} { + childDTypep(dtp); // Only for parser + dtypep(nullptr); // V3Width will resolve + refDTypep(nullptr); + } + AstMemberDType(FileLine* fl, const string& name, AstNodeDType* dtp) + : ASTGEN_SUPER_MemberDType(fl) + , m_name{name} { + UASSERT(dtp, "AstMember created with no dtype"); + refDTypep(dtp); + dtypep(this); + widthFromSub(subDTypep()); + } + ASTGEN_MEMBERS_MemberDType; + string name() const override { return m_name; } // * = Var name + bool hasDType() const override { return true; } + bool maybePointedTo() const override { return true; } + const char* broken() const override { + BROKEN_RTN(m_refDTypep && !m_refDTypep->brokeExists()); + return nullptr; + } + void cloneRelink() override { + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); + } + AstNodeDType* getChildDTypep() const override { return childDTypep(); } + AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } + void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } + bool similarDType(AstNodeDType* samep) const override { return this == samep; } + // + // (Slow) recurse down to find basic data type (Note don't need virtual - + // AstVar isn't a NodeDType) + AstBasicDType* basicp() const override { return subDTypep()->basicp(); } + // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType) + AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } + AstNodeDType* skipRefp() const override { return subDTypep()->skipRefp(); } + AstNodeDType* skipRefToConstp() const override { return subDTypep()->skipRefToConstp(); } + AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); } + // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) + int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } + // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... + int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } + // METHODS + void name(const string& name) override { m_name = name; } + void tag(const string& text) override { m_tag = text; } + string tag() const override { return m_tag; } + int lsb() const { return m_lsb; } + void lsb(int lsb) { m_lsb = lsb; } + bool isCompound() const override { + v3fatalSrc("call isCompound on subdata type, not reference"); + return false; + } +}; +class AstParamTypeDType final : public AstNodeDType { + // Parents: MODULE + // A parameter type statement; much like a var or typedef + // @astgen op1 := childDTypep : Optional[AstNodeDType] +private: + const VVarType m_varType; // Type of variable (for localparam vs. param) + string m_name; // Name of variable +public: + AstParamTypeDType(FileLine* fl, VVarType type, const string& name, VFlagChildDType, + AstNodeDType* dtp) + : ASTGEN_SUPER_ParamTypeDType(fl) + , m_varType{type} + , m_name{name} { + childDTypep(dtp); // Only for parser + dtypep(nullptr); // V3Width will resolve + } + ASTGEN_MEMBERS_ParamTypeDType; + AstNodeDType* getChildDTypep() const override { return childDTypep(); } + AstNodeDType* subDTypep() const override { return dtypep() ? dtypep() : childDTypep(); } + AstBasicDType* basicp() const override { return subDTypep()->basicp(); } + AstNodeDType* skipRefp() const override { return subDTypep()->skipRefp(); } + AstNodeDType* skipRefToConstp() const override { return subDTypep()->skipRefToConstp(); } + AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); } + bool similarDType(AstNodeDType* samep) const override { + const AstParamTypeDType* const sp = static_cast(samep); + return type() == samep->type() && sp + && this->subDTypep()->skipRefp()->similarDType(sp->subDTypep()->skipRefp()); + } + int widthAlignBytes() const override { return dtypep()->widthAlignBytes(); } + int widthTotalBytes() const override { return dtypep()->widthTotalBytes(); } + // METHODS + string name() const override { return m_name; } + bool maybePointedTo() const override { return true; } + bool hasDType() const override { return true; } + void name(const string& flag) override { m_name = flag; } + VVarType varType() const { return m_varType; } // * = Type of variable + bool isParam() const { return true; } + bool isGParam() const { return (varType() == VVarType::GPARAM); } + bool isCompound() const override { + v3fatalSrc("call isCompound on subdata type, not reference"); + return false; + } +}; +class AstParseTypeDType final : public AstNodeDType { + // Parents: VAR + // During parsing, this indicates the type of a parameter is a "parameter type" + // e.g. the data type is a container of any data type +public: + explicit AstParseTypeDType(FileLine* fl) + : ASTGEN_SUPER_ParseTypeDType(fl) {} + ASTGEN_MEMBERS_ParseTypeDType; + AstNodeDType* dtypep() const { return nullptr; } + // METHODS + bool similarDType(AstNodeDType* samep) const override { return this == samep; } + AstBasicDType* basicp() const override { return nullptr; } + AstNodeDType* skipRefp() const override { return nullptr; } + // cppcheck-suppress csyleCast + AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + // cppcheck-suppress csyleCast + AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + int widthAlignBytes() const override { return 0; } + int widthTotalBytes() const override { return 0; } + bool isCompound() const override { + v3fatalSrc("call isCompound on subdata type, not reference"); + return false; + } +}; +class AstQueueDType final : public AstNodeDType { + // Queue array data type, ie "[ $ ]" + // @astgen op1 := childDTypep : Optional[AstNodeDType] // moved to refDTypep() in V3Width + // @astgen op2 := boundp : Optional[AstNode] +private: + AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing) +public: + AstQueueDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* boundp) + : ASTGEN_SUPER_QueueDType(fl) { + this->childDTypep(dtp); + this->boundp(boundp); + refDTypep(nullptr); + dtypep(nullptr); // V3Width will resolve + } + AstQueueDType(FileLine* fl, AstNodeDType* dtp, AstNode* boundp) + : ASTGEN_SUPER_QueueDType(fl) { + this->boundp(boundp); + refDTypep(dtp); + dtypep(dtp); + } + ASTGEN_MEMBERS_QueueDType; + const char* broken() const override { + BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) + || (!m_refDTypep && childDTypep()))); + return nullptr; + } + void cloneRelink() override { + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); + } + bool same(const AstNode* samep) const override { + const AstQueueDType* const asamep = static_cast(samep); + if (!asamep->subDTypep()) return false; + return (subDTypep() == asamep->subDTypep()); + } + bool similarDType(AstNodeDType* samep) const override { + const AstQueueDType* const asamep = static_cast(samep); + return type() == samep->type() && asamep->subDTypep() + && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); + } + void dumpSmall(std::ostream& str) const override; + string prettyDTypeName() const override; + AstNodeDType* getChildDTypep() const override { return childDTypep(); } + AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + inline int boundConst() const; + AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } + void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } + // METHODS + AstBasicDType* basicp() const override { return nullptr; } + // cppcheck-suppress csyleCast + AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + // cppcheck-suppress csyleCast + AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + // cppcheck-suppress csyleCast + AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } + int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } + bool isCompound() const override { return true; } +}; +class AstRefDType final : public AstNodeDType { + // @astgen op1 := typeofp : Optional[AstNode] + // @astgen op2 := classOrPackageOpp : Optional[AstNode] + // @astgen op3 := paramsp : List[AstPin] +private: + // Pre-Width must reference the Typeref, not what it points to, as some child + // types like AstBracketArrayType will disappear and can't lose the handle + AstTypedef* m_typedefp = nullptr; // referenced type + // Post-width typedefs are removed and point to type directly + AstNodeDType* m_refDTypep = nullptr; // data type pointed to, BELOW the AstTypedef + string m_name; // Name of an AstTypedef + AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy +public: + AstRefDType(FileLine* fl, const string& name) + : ASTGEN_SUPER_RefDType(fl) + , m_name{name} {} + AstRefDType(FileLine* fl, const string& name, AstNode* classOrPackagep, AstPin* paramsp) + : ASTGEN_SUPER_RefDType(fl) + , m_name{name} { + this->classOrPackageOpp(classOrPackagep); + addParamsp(paramsp); + } + class FlagTypeOfExpr {}; // type(expr) for parser only + AstRefDType(FileLine* fl, FlagTypeOfExpr, AstNode* typeofp) + : ASTGEN_SUPER_RefDType(fl) { + this->typeofp(typeofp); + } + ASTGEN_MEMBERS_RefDType; + // METHODS + const char* broken() const override; + void cloneRelink() override; + bool same(const AstNode* samep) const override { + const AstRefDType* const asamep = static_cast(samep); + return (m_typedefp == asamep->m_typedefp && m_refDTypep == asamep->m_refDTypep + && m_name == asamep->m_name && m_classOrPackagep == asamep->m_classOrPackagep); + } + bool similarDType(AstNodeDType* samep) const override { + return skipRefp()->similarDType(samep->skipRefp()); + } + void dump(std::ostream& str = std::cout) const override; + string name() const override { return m_name; } + string prettyDTypeName() const override { + return subDTypep() ? subDTypep()->name() : prettyName(); + } + AstBasicDType* basicp() const override { + return subDTypep() ? subDTypep()->basicp() : nullptr; + } + AstNodeDType* subDTypep() const override; + AstNodeDType* skipRefp() const override { + // Skip past both the Ref and the Typedef + if (subDTypep()) { + return subDTypep()->skipRefp(); + } else { + v3fatalSrc("Typedef not linked"); + return nullptr; + } + } + AstNodeDType* skipRefToConstp() const override { + if (subDTypep()) { + return subDTypep()->skipRefToConstp(); + } else { + v3fatalSrc("Typedef not linked"); + return nullptr; + } + } + AstNodeDType* skipRefToEnump() const override { + if (subDTypep()) { + return subDTypep()->skipRefToEnump(); + } else { + v3fatalSrc("Typedef not linked"); + return nullptr; + } + } + int widthAlignBytes() const override { return dtypeSkipRefp()->widthAlignBytes(); } + int widthTotalBytes() const override { return dtypeSkipRefp()->widthTotalBytes(); } + void name(const string& flag) override { m_name = flag; } + AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } + AstTypedef* typedefp() const { return m_typedefp; } + void typedefp(AstTypedef* nodep) { m_typedefp = nodep; } + AstNodeDType* refDTypep() const { return m_refDTypep; } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + AstNodeDType* virtRefDTypep() const override { return refDTypep(); } + void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } + AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } + void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } + bool isCompound() const override { + v3fatalSrc("call isCompound on subdata type, not reference"); + return false; + } +}; +class AstUnsizedArrayDType final : public AstNodeDType { + // Unsized/open-range Array data type, ie "some_dtype var_name []" + // @astgen op1 := childDTypep : Optional[AstNodeDType] // moved to refDTypep() in V3Width +private: + AstNodeDType* m_refDTypep; // Elements of this type (after widthing) +public: + AstUnsizedArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) + : ASTGEN_SUPER_UnsizedArrayDType(fl) { + childDTypep(dtp); // Only for parser + refDTypep(nullptr); + dtypep(nullptr); // V3Width will resolve + } + ASTGEN_MEMBERS_UnsizedArrayDType; + const char* broken() const override { + BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) + || (!m_refDTypep && childDTypep()))); + return nullptr; + } + void cloneRelink() override { + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); + } + bool same(const AstNode* samep) const override; + bool similarDType(AstNodeDType* samep) const override; + void dumpSmall(std::ostream& str) const override; + AstNodeDType* getChildDTypep() const override { return childDTypep(); } + AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } + void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } + // METHODS + AstBasicDType* basicp() const override { return subDTypep()->basicp(); } + AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } + int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } + bool isCompound() const override { return true; } +}; +class AstVoidDType final : public AstNodeDType { + // For e.g. a function returning void +public: + explicit AstVoidDType(FileLine* fl) + : ASTGEN_SUPER_VoidDType(fl) { + dtypep(this); + } + ASTGEN_MEMBERS_VoidDType; + void dumpSmall(std::ostream& str) const override; + bool hasDType() const override { return true; } + bool maybePointedTo() const override { return true; } + bool undead() const override { return true; } + AstNodeDType* subDTypep() const override { return nullptr; } + AstNodeDType* virtRefDTypep() const override { return nullptr; } + void virtRefDTypep(AstNodeDType* nodep) override {} + bool similarDType(AstNodeDType* samep) const override { return this == samep; } + AstBasicDType* basicp() const override { return nullptr; } + // cppcheck-suppress csyleCast + AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + // cppcheck-suppress csyleCast + AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + // cppcheck-suppress csyleCast + AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + int widthAlignBytes() const override { return 1; } + int widthTotalBytes() const override { return 1; } + bool isCompound() const override { return false; } +}; +class AstWildcardArrayDType final : public AstNodeDType { + // Wildcard index type associative array data type, ie "some_dtype var_name [*]" + // @astgen op1 := childDTypep : Optional[AstNodeDType] // moved to refDTypep() in V3Width +private: + AstNodeDType* m_refDTypep; // Elements of this type (after widthing) +public: + AstWildcardArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) + : ASTGEN_SUPER_WildcardArrayDType(fl) { + childDTypep(dtp); // Only for parser + refDTypep(nullptr); + dtypep(nullptr); // V3Width will resolve + } + ASTGEN_MEMBERS_WildcardArrayDType; + const char* broken() const override { + BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) + || (!m_refDTypep && childDTypep()))); + return nullptr; + } + void cloneRelink() override { + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); + } + bool same(const AstNode* samep) const override; + bool similarDType(AstNodeDType* samep) const override; + void dumpSmall(std::ostream& str) const override; + AstNodeDType* getChildDTypep() const override { return childDTypep(); } + AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); } + void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } + AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } + void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } + // METHODS + AstBasicDType* basicp() const override { return subDTypep()->basicp(); } + AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + int widthAlignBytes() const override { return sizeof(std::map); } + int widthTotalBytes() const override { return sizeof(std::map); } + bool isCompound() const override { return true; } +}; + +// === AstNodeArrayDType === +class AstPackArrayDType final : public AstNodeArrayDType { + // Packed array data type, ie "some_dtype [2:0] var_name" +public: + inline AstPackArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstRange* rangep); + inline AstPackArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep); + ASTGEN_MEMBERS_PackArrayDType; + string prettyDTypeName() const override; + bool isCompound() const override { return false; } +}; +class AstUnpackArrayDType final : public AstNodeArrayDType { + // Array data type, ie "some_dtype var_name [2:0]" + bool m_isCompound = false; // Non-POD subDType, or parent requires compound +public: + AstUnpackArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstRange* rangep) + : ASTGEN_SUPER_UnpackArrayDType(fl) { + this->childDTypep(dtp); // Only for parser + this->rangep(rangep); + refDTypep(nullptr); + dtypep(nullptr); // V3Width will resolve + // For backward compatibility AstNodeArrayDType and others inherit + // width and signing from the subDType/base type + widthFromSub(subDTypep()); + } + AstUnpackArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep) + : ASTGEN_SUPER_UnpackArrayDType(fl) { + this->rangep(rangep); + refDTypep(dtp); + dtypep(this); + // For backward compatibility AstNodeArrayDType and others inherit + // width and signing from the subDType/base type + widthFromSub(subDTypep()); + } + ASTGEN_MEMBERS_UnpackArrayDType; + string prettyDTypeName() const override; + bool same(const AstNode* samep) const override { + const AstUnpackArrayDType* const sp = static_cast(samep); + return m_isCompound == sp->m_isCompound; + } + // Outer dimension comes first. The first element is this node. + std::vector unpackDimensions(); + void isCompound(bool flag) { m_isCompound = flag; } + bool isCompound() const override { return m_isCompound; } +}; + +// === AstNodeUOrStructDType === +class AstStructDType final : public AstNodeUOrStructDType { +public: + // VSigning below is mispurposed to indicate if packed or not + AstStructDType(FileLine* fl, VSigning numericUnpack) + : ASTGEN_SUPER_StructDType(fl, numericUnpack) {} + ASTGEN_MEMBERS_StructDType; + string verilogKwd() const override { return "struct"; } +}; +class AstUnionDType final : public AstNodeUOrStructDType { +public: + // UNSUP: bool isTagged; + // VSigning below is mispurposed to indicate if packed or not + AstUnionDType(FileLine* fl, VSigning numericUnpack) + : ASTGEN_SUPER_UnionDType(fl, numericUnpack) {} + ASTGEN_MEMBERS_UnionDType; + string verilogKwd() const override { return "union"; } +}; + +#endif // Guard diff --git a/src/V3AstNodeMath.h b/src/V3AstNodeMath.h new file mode 100644 index 000000000..977a49b96 --- /dev/null +++ b/src/V3AstNodeMath.h @@ -0,0 +1,4287 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: AstNode sub-types representing expressions +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2022 by Wilson Snyder. This program is free software; you +// can redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* +// +// This files contains all 'AstNode' sub-types that representing expressions, +// i.e.: those constructs that evaluate to [a possible void/unit] value. The +// root of the hierarchy is 'AstNodeMath', which could also be called +// 'AstNodeExpr'. +// +// Warning: Although the above is what we are aiming for, currently there are +// some 'AstNode' sub-types defined elsewhere, that represent expressions but +// are not part of the `AstNodeMath` hierarchy (e.g.: 'AstNodeCall' and its +// sub-types). These should eventually be fixed and moved under 'AstNodeMath'. +// +//************************************************************************* + +#ifndef VERILATOR_V3ASTNODEMATH_H_ +#define VERILATOR_V3ASTNODEMATH_H_ + +#ifndef VERILATOR_V3AST_H_ +#error "Use V3Ast.h as the include" +#include "V3Ast.h" // This helps code analysis tools pick up symbols in V3Ast.h +#define VL_NOT_FINAL // This #define fixes broken code folding in the CLion IDE +#endif + +// === Abstract base node types (AstNode*) ===================================== + +class AstNodeMath VL_NOT_FINAL : public AstNode { + // Math -- anything that's part of an expression tree +protected: + AstNodeMath(VNType t, FileLine* fl) + : AstNode{t, fl} {} + +public: + ASTGEN_MEMBERS_NodeMath; + // METHODS + void dump(std::ostream& str) const override; + bool hasDType() const override { return true; } + virtual string emitVerilog() = 0; /// Format string for verilog writing; see V3EmitV + // For documentation on emitC format see EmitCFunc::emitOpName + virtual string emitC() = 0; + virtual string emitSimpleOperator() { return ""; } // "" means not ok to use + virtual bool emitCheckMaxWords() { return false; } // Check VL_MULS_MAX_WORDS + virtual bool cleanOut() const = 0; // True if output has extra upper bits zero + // Someday we will generically support data types on every math node + // Until then isOpaque indicates we shouldn't constant optimize this node type + bool isOpaque() const { return VN_IS(this, CvtPackString); } +}; +class AstNodeBiop VL_NOT_FINAL : public AstNodeMath { + // Binary expression + // @astgen op1 := lhsp : AstNode + // @astgen op2 := rhsp : AstNode +protected: + AstNodeBiop(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : AstNodeMath{t, fl} { + this->lhsp(lhsp); + this->rhsp(rhsp); + } + +public: + ASTGEN_MEMBERS_NodeBiop; + // Clone single node, just get same type back. + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) = 0; + // METHODS + // Set out to evaluation of a AstConst'ed + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) = 0; + virtual bool cleanLhs() const = 0; // True if LHS must have extra upper bits zero + virtual bool cleanRhs() const = 0; // True if RHS must have extra upper bits zero + virtual bool sizeMattersLhs() const = 0; // True if output result depends on lhs size + virtual bool sizeMattersRhs() const = 0; // True if output result depends on rhs size + virtual bool doubleFlavor() const { return false; } // D flavor of nodes with both flavors? + // Signed flavor of nodes with both flavors? + virtual bool signedFlavor() const { return false; } + virtual bool stringFlavor() const { return false; } // N flavor of nodes with both flavors? + int instrCount() const override { return widthInstrs(); } + bool same(const AstNode*) const override { return true; } +}; +class AstNodeBiCom VL_NOT_FINAL : public AstNodeBiop { + // Binary math with commutative properties +protected: + AstNodeBiCom(VNType t, FileLine* fl, AstNode* lhs, AstNode* rhs) + : AstNodeBiop{t, fl, lhs, rhs} {} + +public: + ASTGEN_MEMBERS_NodeBiCom; +}; +class AstNodeBiComAsv VL_NOT_FINAL : public AstNodeBiCom { + // Binary math with commutative & associative properties +protected: + AstNodeBiComAsv(VNType t, FileLine* fl, AstNode* lhs, AstNode* rhs) + : AstNodeBiCom{t, fl, lhs, rhs} {} + +public: + ASTGEN_MEMBERS_NodeBiComAsv; +}; +class AstNodeSel VL_NOT_FINAL : public AstNodeBiop { + // Single bit range extraction, perhaps with non-constant selection or array selection + // @astgen alias op1 := fromp // Expression we are indexing into + // @astgen alias op2 := bitp // The index // TOOD: rename to idxp +protected: + AstNodeSel(VNType t, FileLine* fl, AstNode* fromp, AstNode* bitp) + : AstNodeBiop{t, fl, fromp, bitp} {} + +public: + ASTGEN_MEMBERS_NodeSel; + int bitConst() const; + bool hasDType() const override { return true; } +}; +class AstNodeStream VL_NOT_FINAL : public AstNodeBiop { + // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() +protected: + AstNodeStream(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : AstNodeBiop{t, fl, lhsp, rhsp} { + if (lhsp->dtypep()) dtypeSetLogicSized(lhsp->dtypep()->width(), VSigning::UNSIGNED); + } + +public: + ASTGEN_MEMBERS_NodeStream; +}; +class AstNodeSystemBiop VL_NOT_FINAL : public AstNodeBiop { +public: + AstNodeSystemBiop(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : AstNodeBiop(t, fl, lhsp, rhsp) { + dtypeSetDouble(); + } + ASTGEN_MEMBERS_NodeSystemBiop; + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_DBL_TRIG; } + bool doubleFlavor() const override { return true; } +}; +class AstNodeQuadop VL_NOT_FINAL : public AstNodeMath { + // 4-ary expression + // @astgen op1 := lhsp : AstNode + // @astgen op2 := rhsp : AstNode + // @astgen op3 := thsp : AstNode + // @astgen op4 := fhsp : AstNode +protected: + AstNodeQuadop(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp, + AstNode* fhsp) + : AstNodeMath{t, fl} { + this->lhsp(lhsp); + this->rhsp(rhsp); + this->thsp(thsp); + this->fhsp(fhsp); + } + +public: + ASTGEN_MEMBERS_NodeQuadop; + // METHODS + // Set out to evaluation of a AstConst'ed + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths, const V3Number& fhs) + = 0; + virtual bool cleanLhs() const = 0; // True if LHS must have extra upper bits zero + virtual bool cleanRhs() const = 0; // True if RHS must have extra upper bits zero + virtual bool cleanThs() const = 0; // True if THS must have extra upper bits zero + virtual bool cleanFhs() const = 0; // True if THS must have extra upper bits zero + virtual bool sizeMattersLhs() const = 0; // True if output result depends on lhs size + virtual bool sizeMattersRhs() const = 0; // True if output result depends on rhs size + virtual bool sizeMattersThs() const = 0; // True if output result depends on ths size + virtual bool sizeMattersFhs() const = 0; // True if output result depends on ths size + int instrCount() const override { return widthInstrs(); } + bool same(const AstNode*) const override { return true; } +}; +class AstNodeTermop VL_NOT_FINAL : public AstNodeMath { + // Terminal operator -- a operator with no "inputs" +protected: + AstNodeTermop(VNType t, FileLine* fl) + : AstNodeMath{t, fl} {} + +public: + ASTGEN_MEMBERS_NodeTermop; + // Know no children, and hot function, so skip iterator for speed + // cppcheck-suppress functionConst + void iterateChildren(VNVisitor& v) {} + void dump(std::ostream& str) const override; +}; +class AstNodeTriop VL_NOT_FINAL : public AstNodeMath { + // Ternary expression + // @astgen op1 := lhsp : AstNode + // @astgen op2 := rhsp : AstNode + // @astgen op3 := thsp : AstNode +protected: + AstNodeTriop(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) + : AstNodeMath{t, fl} { + this->lhsp(lhsp); + this->rhsp(rhsp); + this->thsp(thsp); + } + +public: + ASTGEN_MEMBERS_NodeTriop; + // METHODS + void dump(std::ostream& str) const override; + // Set out to evaluation of a AstConst'ed + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) + = 0; + virtual bool cleanLhs() const = 0; // True if LHS must have extra upper bits zero + virtual bool cleanRhs() const = 0; // True if RHS must have extra upper bits zero + virtual bool cleanThs() const = 0; // True if THS must have extra upper bits zero + virtual bool sizeMattersLhs() const = 0; // True if output result depends on lhs size + virtual bool sizeMattersRhs() const = 0; // True if output result depends on rhs size + virtual bool sizeMattersThs() const = 0; // True if output result depends on ths size + int instrCount() const override { return widthInstrs(); } + bool same(const AstNode*) const override { return true; } +}; +class AstNodeCond VL_NOT_FINAL : public AstNodeTriop { + // @astgen alias op1 := condp + // @astgen alias op2 := thenp + // @astgen alias op3 := elsep +protected: + AstNodeCond(VNType t, FileLine* fl, AstNode* condp, AstNode* thenp, AstNode* elsep) + : AstNodeTriop{t, fl, condp, thenp, elsep} { + if (thenp) { + dtypeFrom(thenp); + } else if (elsep) { + dtypeFrom(elsep); + } + } + +public: + ASTGEN_MEMBERS_NodeCond; + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) override; + string emitVerilog() override { return "%k(%l %f? %r %k: %t)"; } + string emitC() override { return "VL_COND_%nq%lq%rq%tq(%nw, %P, %li, %ri, %ti)"; } + bool cleanOut() const override { return false; } // clean if e1 & e2 clean + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return false; } + bool cleanThs() const override { return false; } // Propagates up + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + bool sizeMattersThs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_BRANCH; } + virtual AstNode* cloneType(AstNode* condp, AstNode* thenp, AstNode* elsep) = 0; +}; +class AstNodeUniop VL_NOT_FINAL : public AstNodeMath { + // Unary expression + // @astgen op1 := lhsp : AstNode +protected: + AstNodeUniop(VNType t, FileLine* fl, AstNode* lhsp) + : AstNodeMath{t, fl} { + dtypeFrom(lhsp); + this->lhsp(lhsp); + } + +public: + ASTGEN_MEMBERS_NodeUniop; + // METHODS + void dump(std::ostream& str) const override; + // Set out to evaluation of a AstConst'ed lhs + virtual void numberOperate(V3Number& out, const V3Number& lhs) = 0; + virtual bool cleanLhs() const = 0; + virtual bool sizeMattersLhs() const = 0; // True if output result depends on lhs size + virtual bool doubleFlavor() const { return false; } // D flavor of nodes with both flavors? + // Signed flavor of nodes with both flavors? + virtual bool signedFlavor() const { return false; } + virtual bool stringFlavor() const { return false; } // N flavor of nodes with both flavors? + int instrCount() const override { return widthInstrs(); } + bool same(const AstNode*) const override { return true; } +}; +class AstNodeSystemUniop VL_NOT_FINAL : public AstNodeUniop { +public: + AstNodeSystemUniop(VNType t, FileLine* fl, AstNode* lhsp) + : AstNodeUniop(t, fl, lhsp) { + dtypeSetDouble(); + } + ASTGEN_MEMBERS_NodeSystemUniop; + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_DBL_TRIG; } + bool doubleFlavor() const override { return true; } +}; +class AstNodeVarRef VL_NOT_FINAL : public AstNodeMath { + // An AstVarRef or AstVarXRef +private: + VAccess m_access; // Left hand side assignment + AstVar* m_varp; // [AfterLink] Pointer to variable itself + AstVarScope* m_varScopep = nullptr; // Varscope for hierarchy + AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy + string m_name; // Name of variable + string m_selfPointer; // Output code object pointer (e.g.: 'this') + +protected: + AstNodeVarRef(VNType t, FileLine* fl, const string& name, const VAccess& access) + : AstNodeMath{t, fl} + , m_access{access} + , m_name{name} { + varp(nullptr); + } + AstNodeVarRef(VNType t, FileLine* fl, const string& name, AstVar* varp, const VAccess& access) + : AstNodeMath{t, fl} + , m_access{access} + , m_name{name} { + // May have varp==nullptr + this->varp(varp); + } + +public: + ASTGEN_MEMBERS_NodeVarRef; + void dump(std::ostream& str) const override; + bool hasDType() const override { return true; } + const char* broken() const override; + int instrCount() const override { return widthInstrs(); } + void cloneRelink() override; + string name() const override { return m_name; } // * = Var name + void name(const string& name) override { m_name = name; } + VAccess access() const { return m_access; } + void access(const VAccess& flag) { m_access = flag; } // Avoid using this; Set in constructor + AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable + void varp(AstVar* varp) { + m_varp = varp; + dtypeFrom((AstNode*)varp); + } + AstVarScope* varScopep() const { return m_varScopep; } + void varScopep(AstVarScope* varscp) { m_varScopep = varscp; } + string selfPointer() const { return m_selfPointer; } + void selfPointer(const string& value) { m_selfPointer = value; } + string selfPointerProtect(bool useSelfForThis) const; + AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } + void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } + // Know no children, and hot function, so skip iterator for speed + // cppcheck-suppress functionConst + void iterateChildren(VNVisitor& v) {} +}; + +// === Concrete node types ===================================================== + +// === AstNodeMath === +class AstAddrOfCFunc final : public AstNodeMath { + // Get address of CFunc +private: + AstCFunc* m_funcp; // Pointer to function itself + +public: + AstAddrOfCFunc(FileLine* fl, AstCFunc* funcp) + : ASTGEN_SUPER_AddrOfCFunc(fl) + , m_funcp{funcp} { + dtypep(findCHandleDType()); + } + +public: + ASTGEN_MEMBERS_AddrOfCFunc; + void cloneRelink() override; + const char* broken() const override; + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + AstCFunc* funcp() const { return m_funcp; } +}; +class AstCMath final : public AstNodeMath { + // @astgen op1 := exprsp : List[AstNode] // Expressions to print +private: + const bool m_cleanOut; + bool m_pure; // Pure optimizable +public: + // Emit C textual math function (like AstUCFunc) + AstCMath(FileLine* fl, AstNode* exprsp) + : ASTGEN_SUPER_CMath(fl) + , m_cleanOut{true} + , m_pure{false} { + addExprsp(exprsp); + dtypeFrom(exprsp); + } + inline AstCMath(FileLine* fl, const string& textStmt, int setwidth, bool cleanOut = true); + ASTGEN_MEMBERS_CMath; + bool isGateOptimizable() const override { return m_pure; } + bool isPredictOptimizable() const override { return m_pure; } + bool cleanOut() const override { return m_cleanOut; } + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool same(const AstNode* /*samep*/) const override { return true; } + bool pure() const { return m_pure; } + void pure(bool flag) { m_pure = flag; } +}; +class AstConsAssoc final : public AstNodeMath { + // Construct an assoc array and return object, '{} + // @astgen op1 := defaultp : Optional[AstNode] +public: + AstConsAssoc(FileLine* fl, AstNode* defaultp) + : ASTGEN_SUPER_ConsAssoc(fl) { + this->defaultp(defaultp); + } + ASTGEN_MEMBERS_ConsAssoc; + string emitVerilog() override { return "'{}"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + int instrCount() const override { return widthInstrs(); } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstConsDynArray final : public AstNodeMath { + // Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs} + // @astgen op1 := lhsp : Optional[AstNode] + // @astgen op2 := rhsp : Optional[AstNode] +public: + explicit AstConsDynArray(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr) + : ASTGEN_SUPER_ConsDynArray(fl) { + this->lhsp(lhsp); + this->rhsp(rhsp); + } + ASTGEN_MEMBERS_ConsDynArray; + string emitVerilog() override { return "'{%l, %r}"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + int instrCount() const override { return widthInstrs(); } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstConsQueue final : public AstNodeMath { + // Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs} + // @astgen op1 := lhsp : Optional[AstNode] + // @astgen op2 := rhsp : Optional[AstNode] +public: + explicit AstConsQueue(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr) + : ASTGEN_SUPER_ConsQueue(fl) { + this->lhsp(lhsp); + this->rhsp(rhsp); + } + ASTGEN_MEMBERS_ConsQueue; + string emitVerilog() override { return "'{%l, %r}"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + int instrCount() const override { return widthInstrs(); } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstConsWildcard final : public AstNodeMath { + // Construct a wildcard assoc array and return object, '{} + // @astgen op1 := defaultp : Optional[AstNode] +public: + AstConsWildcard(FileLine* fl, AstNode* defaultp) + : ASTGEN_SUPER_ConsWildcard(fl) { + this->defaultp(defaultp); + } + ASTGEN_MEMBERS_ConsWildcard; + string emitVerilog() override { return "'{}"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + int instrCount() const override { return widthInstrs(); } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstConst final : public AstNodeMath { + // A constant +private: + V3Number m_num; // Constant value + void initWithNumber() { + if (m_num.isDouble()) { + dtypeSetDouble(); + } else if (m_num.isString()) { + dtypeSetString(); + } else { + dtypeSetLogicUnsized(m_num.width(), (m_num.sized() ? 0 : m_num.widthMin()), + VSigning::fromBool(m_num.isSigned())); + } + m_num.nodep(this); + } + +public: + AstConst(FileLine* fl, const V3Number& num) + : ASTGEN_SUPER_Const(fl) + , m_num(num) { + initWithNumber(); + } + class WidthedValue {}; // for creator type-overload selection + AstConst(FileLine* fl, WidthedValue, int width, uint32_t value) + : ASTGEN_SUPER_Const(fl) + , m_num(this, width, value) { + initWithNumber(); + } + class DTyped {}; // for creator type-overload selection + // Zero/empty constant with a type matching nodetypep + AstConst(FileLine* fl, DTyped, const AstNodeDType* nodedtypep) + : ASTGEN_SUPER_Const(fl) + , m_num(this, nodedtypep) { + initWithNumber(); + } + class StringToParse {}; // for creator type-overload selection + AstConst(FileLine* fl, StringToParse, const char* sourcep) + : ASTGEN_SUPER_Const(fl) + , m_num(this, sourcep) { + initWithNumber(); + } + class VerilogStringLiteral {}; // for creator type-overload selection + AstConst(FileLine* fl, VerilogStringLiteral, const string& str) + : ASTGEN_SUPER_Const(fl) + , m_num(V3Number::VerilogStringLiteral(), this, str) { + initWithNumber(); + } + AstConst(FileLine* fl, uint32_t num) + : ASTGEN_SUPER_Const(fl) + , m_num(this, 32, num) { + dtypeSetLogicUnsized(m_num.width(), 0, VSigning::UNSIGNED); + } + class Unsized32 {}; // for creator type-overload selection + AstConst(FileLine* fl, Unsized32, uint32_t num) // Unsized 32-bit integer of specified value + : ASTGEN_SUPER_Const(fl) + , m_num(this, 32, num) { + m_num.width(32, false); + dtypeSetLogicUnsized(32, m_num.widthMin(), VSigning::UNSIGNED); + } + class Signed32 {}; // for creator type-overload selection + AstConst(FileLine* fl, Signed32, int32_t num) // Signed 32-bit integer of specified value + : ASTGEN_SUPER_Const(fl) + , m_num(this, 32, num) { + m_num.width(32, true); + dtypeSetLogicUnsized(32, m_num.widthMin(), VSigning::SIGNED); + } + class Unsized64 {}; // for creator type-overload selection + AstConst(FileLine* fl, Unsized64, uint64_t num) + : ASTGEN_SUPER_Const(fl) + , m_num(this, 64, 0) { + m_num.setQuad(num); + dtypeSetLogicSized(64, VSigning::UNSIGNED); + } + class SizedEData {}; // for creator type-overload selection + AstConst(FileLine* fl, SizedEData, uint64_t num) + : ASTGEN_SUPER_Const(fl) + , m_num(this, VL_EDATASIZE, 0) { + m_num.setQuad(num); + dtypeSetLogicSized(VL_EDATASIZE, VSigning::UNSIGNED); + } + class RealDouble {}; // for creator type-overload selection + AstConst(FileLine* fl, RealDouble, double num) + : ASTGEN_SUPER_Const(fl) + , m_num(this, 64) { + m_num.setDouble(num); + dtypeSetDouble(); + } + class String {}; // for creator type-overload selection + AstConst(FileLine* fl, String, const string& num) + : ASTGEN_SUPER_Const(fl) + , m_num(V3Number::String(), this, num) { + dtypeSetString(); + } + class BitFalse {}; + AstConst(FileLine* fl, BitFalse) // Shorthand const 0, dtype should be a logic of size 1 + : ASTGEN_SUPER_Const(fl) + , m_num(this, 1, 0) { + dtypeSetBit(); + } + // Shorthand const 1 (or with argument 0/1), dtype should be a logic of size 1 + class BitTrue {}; + AstConst(FileLine* fl, BitTrue, bool on = true) + : ASTGEN_SUPER_Const(fl) + , m_num(this, 1, on) { + dtypeSetBit(); + } + class Null {}; + AstConst(FileLine* fl, Null) + : ASTGEN_SUPER_Const(fl) + , m_num(V3Number::Null{}, this) { + dtypeSetBit(); // Events 1 bit, objects 64 bits, so autoExtend=1 and use bit here + initWithNumber(); + } + ASTGEN_MEMBERS_Const; + string name() const override { return num().ascii(); } // * = Value + const V3Number& num() const { return m_num; } // * = Value + V3Number& num() { return m_num; } // * = Value + uint32_t toUInt() const { return num().toUInt(); } + int32_t toSInt() const { return num().toSInt(); } + uint64_t toUQuad() const { return num().toUQuad(); } + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + bool same(const AstNode* samep) const override { + const AstConst* const sp = static_cast(samep); + return num().isCaseEq(sp->num()); + } + int instrCount() const override { return widthInstrs(); } + bool isEqAllOnes() const { return num().isEqAllOnes(width()); } + bool isEqAllOnesV() const { return num().isEqAllOnes(widthMinV()); } + // Parse string and create appropriate type of AstConst. + // May return nullptr on parse failure. + static AstConst* parseParamLiteral(FileLine* fl, const string& literal); +}; +class AstEmptyQueue final : public AstNodeMath { +public: + explicit AstEmptyQueue(FileLine* fl) + : ASTGEN_SUPER_EmptyQueue(fl) {} + ASTGEN_MEMBERS_EmptyQueue; + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitVerilog() override { return "{}"; } + bool same(const AstNode* /*samep*/) const override { return true; } + bool cleanOut() const override { return true; } +}; +class AstEnumItemRef final : public AstNodeMath { +private: + AstEnumItem* m_itemp; // [AfterLink] Pointer to item + AstNodeModule* m_classOrPackagep; // Package hierarchy +public: + AstEnumItemRef(FileLine* fl, AstEnumItem* itemp, AstNodeModule* classOrPackagep) + : ASTGEN_SUPER_EnumItemRef(fl) + , m_itemp{itemp} + , m_classOrPackagep{classOrPackagep} { + dtypeFrom(m_itemp); + } + ASTGEN_MEMBERS_EnumItemRef; + void dump(std::ostream& str) const override; + string name() const override { return itemp()->name(); } + int instrCount() const override { return 0; } + const char* broken() const override; + void cloneRelink() override { + if (m_itemp->clonep()) m_itemp = m_itemp->clonep(); + } + bool same(const AstNode* samep) const override { + const AstEnumItemRef* const sp = static_cast(samep); + return itemp() == sp->itemp(); + } + AstEnumItem* itemp() const { return m_itemp; } + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } + void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } +}; +class AstExprStmt final : public AstNodeMath { + // Perform a statement, often assignment inside an expression/math node, + // the parent gets passed the 'resultp()'. + // resultp is evaluated AFTER the statement(s). + // @astgen op1 := stmtsp : List[AstNode] + // @astgen op2 := resultp : AstNode +public: + AstExprStmt(FileLine* fl, AstNode* stmtsp, AstNode* resultp) + : ASTGEN_SUPER_ExprStmt(fl) { + addStmtsp(stmtsp); + this->resultp(resultp); + dtypeFrom(resultp); + } + ASTGEN_MEMBERS_ExprStmt; + // METHODS + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return false; } + bool same(const AstNode*) const override { return true; } +}; +class AstFError final : public AstNodeMath { + // @astgen op1 := filep : AstNode + // @astgen op2 := strp : AstNode +public: + AstFError(FileLine* fl, AstNode* filep, AstNode* strp) + : ASTGEN_SUPER_FError(fl) { + this->filep(filep); + this->strp(strp); + } + ASTGEN_MEMBERS_FError; + string emitVerilog() override { return "%f$ferror(%l, %r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + virtual bool cleanLhs() const { return true; } + virtual bool sizeMattersLhs() const { return false; } + int instrCount() const override { return widthInstrs() * 64; } + bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstFRead final : public AstNodeMath { + // @astgen op1 := memp : AstNode // VarRef for result + // @astgen op2 := filep : AstNode // file (must be a VarRef) + // @astgen op3 := startp : Optional[AstNode] // Offset + // @astgen op4 := countp : Optional[AstNode] // Size +public: + AstFRead(FileLine* fl, AstNode* memp, AstNode* filep, AstNode* startp, AstNode* countp) + : ASTGEN_SUPER_FRead(fl) { + this->memp(memp); + this->filep(filep); + this->startp(startp); + this->countp(countp); + } + ASTGEN_MEMBERS_FRead; + string verilogKwd() const override { return "$fread"; } + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering + bool isOutputter() const override { return true; } // SPECIAL: makes output + bool cleanOut() const override { return false; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstFRewind final : public AstNodeMath { + // Parents: stmtlist + // @astgen op1 := filep : Optional[AstNode] +public: + AstFRewind(FileLine* fl, AstNode* filep) + : ASTGEN_SUPER_FRewind(fl) { + this->filep(filep); + } + ASTGEN_MEMBERS_FRewind; + string verilogKwd() const override { return "$frewind"; } + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } + bool isOutputter() const override { return true; } + bool isUnlikely() const override { return true; } + bool cleanOut() const override { return false; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstFScanF final : public AstNodeMath { + // @astgen op1 := exprsp : List[AstNode] // VarRefs for results + // @astgen op2 := filep : Optional[AstNode] // file (must be a VarRef) +private: + string m_text; + +public: + AstFScanF(FileLine* fl, const string& text, AstNode* filep, AstNode* exprsp) + : ASTGEN_SUPER_FScanF(fl) + , m_text{text} { + addExprsp(exprsp); + this->filep(filep); + } + ASTGEN_MEMBERS_FScanF; + string name() const override { return m_text; } + string verilogKwd() const override { return "$fscanf"; } + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering + bool isOutputter() const override { return true; } // SPECIAL: makes output + bool cleanOut() const override { return false; } + bool same(const AstNode* samep) const override { + return text() == static_cast(samep)->text(); + } + string text() const { return m_text; } // * = Text to display + void text(const string& text) { m_text = text; } +}; +class AstFSeek final : public AstNodeMath { + // @astgen op1 := filep : AstNode // file (must be a VarRef) + // @astgen op2 := offset : Optional[AstNode] + // @astgen op3 := operation : Optional[AstNode] +public: + AstFSeek(FileLine* fl, AstNode* filep, AstNode* offset, AstNode* operation) + : ASTGEN_SUPER_FSeek(fl) { + this->filep(filep); + this->offset(offset); + this->operation(operation); + } + ASTGEN_MEMBERS_FSeek; + string verilogKwd() const override { return "$fseek"; } + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering + bool isOutputter() const override { return true; } // SPECIAL: makes output + bool cleanOut() const override { return false; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstFTell final : public AstNodeMath { + // Parents: stmtlist + // @astgen op1 := filep : AstNode // file (must be a VarRef) +public: + AstFTell(FileLine* fl, AstNode* filep) + : ASTGEN_SUPER_FTell(fl) { + this->filep(filep); + } + ASTGEN_MEMBERS_FTell; + string verilogKwd() const override { return "$ftell"; } + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } + bool isOutputter() const override { return true; } + bool isUnlikely() const override { return true; } + bool cleanOut() const override { return false; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstFell final : public AstNodeMath { + // Verilog $fell + // @astgen op1 := exprp : AstNode + // @astgen op2 := sentreep : Optional[AstSenTree] +public: + AstFell(FileLine* fl, AstNode* exprp) + : ASTGEN_SUPER_Fell(fl) { + this->exprp(exprp); + } + ASTGEN_MEMBERS_Fell; + string emitVerilog() override { return "$fell(%l)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { V3ERROR_NA_RETURN(""); } + int instrCount() const override { return widthInstrs(); } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstGatePin final : public AstNodeMath { + // Possibly expand a gate primitive input pin value to match the range of the gate primitive + // @astgen op1 := exprp : AstNode // Pin expression + // @astgen op2 := rangep : AstRange // Range of pin +public: + AstGatePin(FileLine* fl, AstNode* exprp, AstRange* rangep) + : ASTGEN_SUPER_GatePin(fl) { + this->exprp(exprp); + this->rangep(rangep); + } + ASTGEN_MEMBERS_GatePin; + string emitVerilog() override { return "%l"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } +}; +class AstImplication final : public AstNodeMath { + // Verilog |-> |=> + // @astgen op1 := lhsp : AstNode + // @astgen op2 := rhsp : AstNode + // @astgen op3 := sentreep : Optional[AstSenTree] +public: + AstImplication(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Implication(fl) { + this->lhsp(lhsp); + this->rhsp(rhsp); + } + ASTGEN_MEMBERS_Implication; + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { V3ERROR_NA_RETURN(""); } + int instrCount() const override { return widthInstrs(); } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstInside final : public AstNodeMath { + // @astgen op1 := exprp : AstNode + // @astgen op2 := itemsp : List[AstNode] +public: + AstInside(FileLine* fl, AstNode* exprp, AstNode* itemsp) + : ASTGEN_SUPER_Inside(fl) { + this->exprp(exprp); + this->addItemsp(itemsp); + dtypeSetBit(); + } + ASTGEN_MEMBERS_Inside; + string emitVerilog() override { return "%l inside { %r }"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return false; } // NA +}; +class AstInsideRange final : public AstNodeMath { + // @astgen op1 := lhsp : AstNode + // @astgen op2 := rhsp : AstNode +public: + AstInsideRange(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_InsideRange(fl) { + this->lhsp(lhsp); + this->rhsp(rhsp); + } + ASTGEN_MEMBERS_InsideRange; + string emitVerilog() override { return "[%l:%r]"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return false; } // NA + // Create AstAnd(AstGte(...), AstLte(...)) + AstNode* newAndFromInside(AstNode* exprp, AstNode* lhsp, AstNode* rhsp); +}; +class AstLambdaArgRef final : public AstNodeMath { + // Lambda argument usage + // These are not AstVarRefs because we need to be able to delete/clone lambdas during + // optimizations and AstVar's are painful to remove. +private: + string m_name; // Name of variable + bool m_index; // Index, not value + +public: + AstLambdaArgRef(FileLine* fl, const string& name, bool index) + : ASTGEN_SUPER_LambdaArgRef(fl) + , m_name{name} + , m_index(index) {} + ASTGEN_MEMBERS_LambdaArgRef; + bool same(const AstNode* /*samep*/) const override { return true; } + string emitVerilog() override { return name(); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + bool hasDType() const override { return true; } + int instrCount() const override { return widthInstrs(); } + string name() const override { return m_name; } // * = Var name + void name(const string& name) override { m_name = name; } + bool index() const { return m_index; } +}; +class AstMemberSel final : public AstNodeMath { + // Parents: math|stmt + // @astgen op1 := fromp : AstNode +private: + // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it + string m_name; + AstVar* m_varp = nullptr; // Post link, variable within class that is target of selection +public: + AstMemberSel(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name) + : ASTGEN_SUPER_MemberSel(fl) + , m_name{name} { + this->fromp(fromp); + dtypep(nullptr); // V3Width will resolve + } + AstMemberSel(FileLine* fl, AstNode* fromp, AstNodeDType* dtp) + : ASTGEN_SUPER_MemberSel(fl) + , m_name{dtp->name()} { + this->fromp(fromp); + dtypep(dtp); + } + ASTGEN_MEMBERS_MemberSel; + void cloneRelink() override; + const char* broken() const override; + void dump(std::ostream& str) const override; + string name() const override { return m_name; } + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return false; } + bool same(const AstNode* samep) const override { return true; } // dtype comparison does it + int instrCount() const override { return widthInstrs(); } + AstVar* varp() const { return m_varp; } + void varp(AstVar* nodep) { m_varp = nodep; } +}; +class AstNewCopy final : public AstNodeMath { + // New as shallow copy + // Parents: math|stmt + // @astgen op1 := rhsp : AstNode +public: + AstNewCopy(FileLine* fl, AstNode* rhsp) + : ASTGEN_SUPER_NewCopy(fl) { + dtypeFrom(rhsp); // otherwise V3Width will resolve + this->rhsp(rhsp); + } + ASTGEN_MEMBERS_NewCopy; + string emitVerilog() override { return "new"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + bool same(const AstNode* /*samep*/) const override { return true; } + int instrCount() const override { return widthInstrs(); } +}; +class AstNewDynamic final : public AstNodeMath { + // New for dynamic array + // Parents: math|stmt + // @astgen op1 := sizep : AstNode + // @astgen op2 := rhsp : Optional[AstNode] +public: + AstNewDynamic(FileLine* fl, AstNode* sizep, AstNode* rhsp) + : ASTGEN_SUPER_NewDynamic(fl) { + dtypeFrom(rhsp); // otherwise V3Width will resolve + this->sizep(sizep); + this->rhsp(rhsp); + } + ASTGEN_MEMBERS_NewDynamic; + string emitVerilog() override { return "new"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + bool same(const AstNode* /*samep*/) const override { return true; } + int instrCount() const override { return widthInstrs(); } +}; +class AstPast final : public AstNodeMath { + // Verilog $past + // @astgen op1 := exprp : AstNode + // @astgen op2 := ticksp : Optional[AstNode] + // @astgen op3 := sentreep : Optional[AstSenTree] +public: + AstPast(FileLine* fl, AstNode* exprp, AstNode* ticksp) + : ASTGEN_SUPER_Past(fl) { + this->exprp(exprp); + this->ticksp(ticksp); + } + ASTGEN_MEMBERS_Past; + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { V3ERROR_NA_RETURN(""); } + int instrCount() const override { return widthInstrs(); } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstPatMember final : public AstNodeMath { + // Verilog '{a} or '{a{b}} + // Parents: AstPattern + // Children: expression, AstPattern, replication count + // Expression to assign or another AstPattern (list if replicated) + // @astgen op1 := lhssp : List[AstNode] + // @astgen op2 := keyp : Optional[AstNode] + // @astgen op3 := repp : Optional[AstNode] // replication count, or nullptr for count 1 +private: + bool m_default = false; + +public: + AstPatMember(FileLine* fl, AstNode* lhssp, AstNode* keyp, AstNode* repp) + : ASTGEN_SUPER_PatMember(fl) { + this->addLhssp(lhssp); + this->keyp(keyp); + this->repp(repp); + } + ASTGEN_MEMBERS_PatMember; + string emitVerilog() override { return lhssp() ? "%f{%r{%k%l}}" : "%l"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { V3ERROR_NA_RETURN(""); } + int instrCount() const override { return widthInstrs() * 2; } + void dump(std::ostream& str = std::cout) const override; + bool isDefault() const { return m_default; } + void isDefault(bool flag) { m_default = flag; } +}; +class AstPattern final : public AstNodeMath { + // Verilog '{a,b,c,d...} + // Parents: AstNodeAssign, AstPattern, ... + // Children: expression, AstPattern, AstPatReplicate + // @astgen op1 := childDTypep : Optional[AstNodeDType] + // @astgen op2 := itemsp : List[AstNode] // AstPatReplicate, AstPatMember, etc +public: + AstPattern(FileLine* fl, AstNode* itemsp) + : ASTGEN_SUPER_Pattern(fl) { + addItemsp(itemsp); + } + ASTGEN_MEMBERS_Pattern; + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { V3ERROR_NA_RETURN(""); } + int instrCount() const override { return widthInstrs(); } + AstNodeDType* getChildDTypep() const override { return childDTypep(); } + virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } +}; +class AstRand final : public AstNodeMath { + // $random/$random(seed) or $urandom/$urandom(seed) + // Return a random number, based upon width() + // @astgen op1 := seedp : Optional[AstNode] +private: + const bool m_urandom = false; // $urandom vs $random + const bool m_reset = false; // Random reset, versus always random +public: + class Reset {}; + AstRand(FileLine* fl, Reset, AstNodeDType* dtp, bool reset) + : ASTGEN_SUPER_Rand(fl) + , m_reset{reset} { + dtypep(dtp); + } + AstRand(FileLine* fl, AstNode* seedp, bool urandom) + : ASTGEN_SUPER_Rand(fl) + , m_urandom{urandom} { + this->seedp(seedp); + } + ASTGEN_MEMBERS_Rand; + string emitVerilog() override { + return seedp() ? (m_urandom ? "%f$urandom(%l)" : "%f$random(%l)") + : (m_urandom ? "%f$urandom()" : "%f$random()"); + } + string emitC() override { + return m_reset ? "VL_RAND_RESET_%nq(%nw, %P)" + : seedp() + ? (urandom() ? "VL_URANDOM_SEEDED_%nq%lq(%li)" : "VL_RANDOM_SEEDED_%nq%lq(%li)") + : isWide() ? "VL_RANDOM_%nq(%nw, %P)" // + : "VL_RANDOM_%nq()"; + } + bool cleanOut() const override { return false; } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + int instrCount() const override { return INSTR_COUNT_PLI; } + bool same(const AstNode* /*samep*/) const override { return true; } + bool combinable(const AstRand* samep) const { + return !seedp() && !samep->seedp() && reset() == samep->reset() + && urandom() == samep->urandom(); + } + bool reset() const { return m_reset; } + bool urandom() const { return m_urandom; } +}; +class AstRose final : public AstNodeMath { + // Verilog $rose + // @astgen op1 := exprp : AstNode + // @astgen op2 := sentreep : Optional[AstSenTree] +public: + AstRose(FileLine* fl, AstNode* exprp) + : ASTGEN_SUPER_Rose(fl) { + this->exprp(exprp); + } + ASTGEN_MEMBERS_Rose; + string emitVerilog() override { return "$rose(%l)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { V3ERROR_NA_RETURN(""); } + int instrCount() const override { return widthInstrs(); } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstSScanF final : public AstNodeMath { + // @astgen op1 := exprsp : List[AstNode] // VarRefs for results + // @astgen op2 := fromp : AstNode +private: + string m_text; + +public: + AstSScanF(FileLine* fl, const string& text, AstNode* fromp, AstNode* exprsp) + : ASTGEN_SUPER_SScanF(fl) + , m_text{text} { + this->addExprsp(exprsp); + this->fromp(fromp); + } + ASTGEN_MEMBERS_SScanF; + string name() const override { return m_text; } + string verilogKwd() const override { return "$sscanf"; } + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering + bool isOutputter() const override { return true; } // SPECIAL: makes output + bool cleanOut() const override { return false; } + bool same(const AstNode* samep) const override { + return text() == static_cast(samep)->text(); + } + string text() const { return m_text; } // * = Text to display + void text(const string& text) { m_text = text; } +}; +class AstSampled final : public AstNodeMath { + // Verilog $sampled + // @astgen op1 := exprp : AstNode +public: + AstSampled(FileLine* fl, AstNode* exprp) + : ASTGEN_SUPER_Sampled(fl) { + this->exprp(exprp); + } + ASTGEN_MEMBERS_Sampled; + string emitVerilog() override { return "$sampled(%l)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { V3ERROR_NA_RETURN(""); } + int instrCount() const override { return 0; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstScopeName final : public AstNodeMath { + // For display %m and DPI context imports + // Parents: DISPLAY + // @astgen op1 := scopeAttrp : List[AstText] + // @astgen op2 := scopeEntrp : List[AstText] +private: + bool m_dpiExport = false; // Is for dpiExport + const bool m_forFormat = false; // Is for a format %m + string scopeNameFormatter(AstText* scopeTextp) const; + string scopePrettyNameFormatter(AstText* scopeTextp) const; + +public: + class ForFormat {}; + AstScopeName(FileLine* fl, bool forFormat) + : ASTGEN_SUPER_ScopeName(fl) + , m_forFormat{forFormat} { + dtypeSetUInt64(); + } + ASTGEN_MEMBERS_ScopeName; + bool same(const AstNode* samep) const override { + return (m_dpiExport == static_cast(samep)->m_dpiExport + && m_forFormat == static_cast(samep)->m_forFormat); + } + string emitVerilog() override { return ""; } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + void dump(std::ostream& str = std::cout) const override; + string scopeSymName() const { // Name for __Vscope variable including children + return scopeNameFormatter(scopeAttrp()); + } + string scopeDpiName() const { // Name for DPI import scope + return scopeNameFormatter(scopeEntrp()); + } + string scopePrettySymName() const { // Name for __Vscope variable including children + return scopePrettyNameFormatter(scopeAttrp()); + } + string scopePrettyDpiName() const { // Name for __Vscope variable including children + return scopePrettyNameFormatter(scopeEntrp()); + } + bool dpiExport() const { return m_dpiExport; } + void dpiExport(bool flag) { m_dpiExport = flag; } + bool forFormat() const { return m_forFormat; } +}; +class AstSetAssoc final : public AstNodeMath { + // Set an assoc array element and return object, '{} + // Parents: math + // @astgen op1 := lhsp : AstNode + // @astgen op2 := keyp : Optional[AstNode] + // @astgen op3 := valuep : AstNode +public: + AstSetAssoc(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* valuep) + : ASTGEN_SUPER_SetAssoc(fl) { + this->lhsp(lhsp); + this->keyp(keyp); + this->valuep(valuep); + } + ASTGEN_MEMBERS_SetAssoc; + string emitVerilog() override { return "'{}"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + int instrCount() const override { return widthInstrs(); } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstSetWildcard final : public AstNodeMath { + // Set a wildcard assoc array element and return object, '{} + // Parents: math + // @astgen op1 := lhsp : AstNode + // @astgen op2 := keyp : Optional[AstNode] + // @astgen op3 := valuep : AstNode +public: + AstSetWildcard(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* valuep) + : ASTGEN_SUPER_SetWildcard(fl) { + this->lhsp(lhsp); + this->keyp(keyp); + this->valuep(valuep); + } + ASTGEN_MEMBERS_SetWildcard; + string emitVerilog() override { return "'{}"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + int instrCount() const override { return widthInstrs(); } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstStable final : public AstNodeMath { + // Verilog $stable + // @astgen op1 := exprp : AstNode + // @astgen op2 := sentreep : Optional[AstSenTree] +public: + AstStable(FileLine* fl, AstNode* exprp) + : ASTGEN_SUPER_Stable(fl) { + this->exprp(exprp); + } + ASTGEN_MEMBERS_Stable; + string emitVerilog() override { return "$stable(%l)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { V3ERROR_NA_RETURN(""); } + int instrCount() const override { return widthInstrs(); } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstSystemF final : public AstNodeMath { + // $system used as function + // @astgen op1 := lhsp : AstNode +public: + AstSystemF(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_SystemF(fl) { + this->lhsp(lhsp); + } + ASTGEN_MEMBERS_SystemF; + string verilogKwd() const override { return "$system"; } + string emitVerilog() override { return verilogKwd(); } + string emitC() override { return "VL_SYSTEM_%nq(%lw, %P)"; } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } + bool isOutputter() const override { return true; } + bool isUnlikely() const override { return true; } + bool cleanOut() const override { return true; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstTestPlusArgs final : public AstNodeMath { + // Search expression. If nullptr then this is a $test$plusargs instead of $value$plusargs. + // @astgen op1 := searchp : Optional[AstNode] +public: + AstTestPlusArgs(FileLine* fl, AstNode* searchp) + : ASTGEN_SUPER_TestPlusArgs(fl) { + this->searchp(searchp); + } + ASTGEN_MEMBERS_TestPlusArgs; + string verilogKwd() const override { return "$test$plusargs"; } + string emitVerilog() override { return verilogKwd(); } + string emitC() override { return "VL_VALUEPLUSARGS_%nq(%lw, %P, nullptr)"; } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool cleanOut() const override { return true; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstUCFunc final : public AstNodeMath { + // User's $c function + // Perhaps this should be an AstNodeListop; but there's only one list math right now + // @astgen op1 := exprsp : List[AstNode] // Expressions to print +public: + AstUCFunc(FileLine* fl, AstNode* exprsp) + : ASTGEN_SUPER_UCFunc(fl) { + this->addExprsp(exprsp); + } + ASTGEN_MEMBERS_UCFunc; + bool cleanOut() const override { return false; } + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs + bool isOutputter() const override { return true; } + bool isGateOptimizable() const override { return false; } + bool isSubstOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + int instrCount() const override { return INSTR_COUNT_PLI; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstUnbounded final : public AstNodeMath { + // A $ in the parser, used for unbounded and queues + // Due to where is used, treated as Signed32 +public: + explicit AstUnbounded(FileLine* fl) + : ASTGEN_SUPER_Unbounded(fl) { + dtypeSetSigned32(); + } + ASTGEN_MEMBERS_Unbounded; + string emitVerilog() override { return "$"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } +}; +class AstValuePlusArgs final : public AstNodeMath { + // Search expression. If nullptr then this is a $test$plusargs instead of $value$plusargs. + // @astgen op1 := searchp : Optional[AstNode] + // @astgen op2 := outp : AstNode // VarRef for result +public: + AstValuePlusArgs(FileLine* fl, AstNode* searchp, AstNode* outp) + : ASTGEN_SUPER_ValuePlusArgs(fl) { + this->searchp(searchp); + this->outp(outp); + } + ASTGEN_MEMBERS_ValuePlusArgs; + string verilogKwd() const override { return "$value$plusargs"; } + string emitVerilog() override { return "%f$value$plusargs(%l, %k%r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return !outp(); } + bool cleanOut() const override { return true; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; + +// === AstNodeBiop === +class AstBufIf1 final : public AstNodeBiop { + // lhs is enable, rhs is data to drive + // Note unlike the Verilog bufif1() UDP, this allows any width; each lhsp + // bit enables respective rhsp bit +public: + AstBufIf1(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_BufIf1(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTGEN_MEMBERS_BufIf1; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstBufIf1(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opBufIf1(lhs, rhs); + } + string emitVerilog() override { return "bufif(%r,%l)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } // Lclean || Rclean + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } // Lclean || Rclean + bool cleanOut() const override { V3ERROR_NA_RETURN(""); } // Lclean || Rclean + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } +}; +class AstCastDynamic final : public AstNodeBiop { + // Verilog $cast used as a function + // Task usage of $cast is converted during parse to assert($cast(...)) + // Parents: MATH + // Children: MATH + // lhsp() is value (we are converting FROM) to match AstCCast etc, this + // is opposite of $cast's order, because the first access is to the + // value reading from. Suggest use fromp()/top() instead of lhsp/rhsp(). +public: + AstCastDynamic(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_CastDynamic(fl, lhsp, rhsp) {} + ASTGEN_MEMBERS_CastDynamic; + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + V3ERROR_NA; + } + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstCastDynamic(this->fileline(), lhsp, rhsp); + } + string emitVerilog() override { return "%f$cast(%r, %l)"; } + string emitC() override { return "VL_DYNAMIC_CAST(%r, %l)"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return widthInstrs() * 20; } + bool isPure() const override { return true; } + AstNode* fromp() const { return lhsp(); } + AstNode* top() const { return rhsp(); } +}; +class AstCompareNN final : public AstNodeBiop { + // Verilog str.compare() and str.icompare() +private: + const bool m_ignoreCase; // True for str.icompare() +public: + AstCompareNN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, bool ignoreCase) + : ASTGEN_SUPER_CompareNN(fl, lhsp, rhsp) + , m_ignoreCase{ignoreCase} { + dtypeSetUInt32(); + } + ASTGEN_MEMBERS_CompareNN; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstCompareNN(this->fileline(), lhsp, rhsp, m_ignoreCase); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opCompareNN(lhs, rhs, m_ignoreCase); + } + string name() const override { return m_ignoreCase ? "icompare" : "compare"; } + string emitVerilog() override { + return m_ignoreCase ? "%k(%l.icompare(%r))" : "%k(%l.compare(%r))"; + } + string emitC() override { + return m_ignoreCase ? "VL_CMP_NN(%li,%ri,true)" : "VL_CMP_NN(%li,%ri,false)"; + } + string emitSimpleOperator() override { return ""; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } +}; +class AstConcat final : public AstNodeBiop { + // If you're looking for {#{}}, see AstReplicate +public: + AstConcat(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Concat(fl, lhsp, rhsp) { + if (lhsp->dtypep() && rhsp->dtypep()) { + dtypeSetLogicSized(lhsp->dtypep()->width() + rhsp->dtypep()->width(), + VSigning::UNSIGNED); + } + } + ASTGEN_MEMBERS_Concat; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstConcat(this->fileline(), lhsp, rhsp); + } + string emitVerilog() override { return "%f{%l, %k%r}"; } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opConcat(lhs, rhs); + } + string emitC() override { return "VL_CONCAT_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return widthInstrs() * 2; } +}; +class AstConcatN final : public AstNodeBiop { + // String concatenate +public: + AstConcatN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_ConcatN(fl, lhsp, rhsp) { + dtypeSetString(); + } + ASTGEN_MEMBERS_ConcatN; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstConcatN(this->fileline(), lhsp, rhsp); + } + string emitVerilog() override { return "%f{%l, %k%r}"; } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opConcatN(lhs, rhs); + } + string emitC() override { return "VL_CONCATN_NNN(%li, %ri)"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_STR; } + bool stringFlavor() const override { return true; } +}; +class AstDiv final : public AstNodeBiop { +public: + AstDiv(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Div(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTGEN_MEMBERS_Div; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstDiv(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opDiv(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f/ %r)"; } + string emitC() override { return "VL_DIV_%nq%lq%rq(%lw, %P, %li, %ri)"; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return true; } + bool sizeMattersRhs() const override { return true; } + int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_DIV; } +}; +class AstDivD final : public AstNodeBiop { +public: + AstDivD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_DivD(fl, lhsp, rhsp) { + dtypeSetDouble(); + } + ASTGEN_MEMBERS_DivD; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstDivD(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opDivD(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f/ %r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { return "/"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_DBL_DIV; } + bool doubleFlavor() const override { return true; } +}; +class AstDivS final : public AstNodeBiop { +public: + AstDivS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_DivS(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTGEN_MEMBERS_DivS; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstDivS(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opDivS(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f/ %r)"; } + string emitC() override { return "VL_DIVS_%nq%lq%rq(%lw, %P, %li, %ri)"; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return true; } + bool sizeMattersRhs() const override { return true; } + int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_DIV; } + bool signedFlavor() const override { return true; } +}; +class AstEqWild final : public AstNodeBiop { + // Note wildcard operator rhs differs from lhs +public: + AstEqWild(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_EqWild(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_EqWild; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstEqWild(this->fileline(), lhsp, rhsp); + } + static AstNodeBiop* newTyped(FileLine* fl, AstNode* lhsp, + AstNode* rhsp); // Return AstEqWild/AstEqD + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opWildEq(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f==? %r)"; } + string emitC() override { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; } + string emitSimpleOperator() override { return "=="; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } +}; +class AstFGetS final : public AstNodeBiop { +public: + AstFGetS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_FGetS(fl, lhsp, rhsp) {} + ASTGEN_MEMBERS_FGetS; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstFGetS(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + V3ERROR_NA; + } + string emitVerilog() override { return "%f$fgets(%l,%r)"; } + string emitC() override { + return strgp()->dtypep()->basicp()->isString() ? "VL_FGETS_NI(%li, %ri)" + : "VL_FGETS_%nqX%rq(%lw, %P, &(%li), %ri)"; + } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return widthInstrs() * 64; } + AstNode* strgp() const { return lhsp(); } + AstNode* filep() const { return rhsp(); } +}; +class AstFUngetC final : public AstNodeBiop { +public: + AstFUngetC(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_FUngetC(fl, lhsp, rhsp) {} + ASTGEN_MEMBERS_FUngetC; + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + V3ERROR_NA; + } + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstFUngetC(this->fileline(), lhsp, rhsp); + } + string emitVerilog() override { return "%f$ungetc(%r, %l)"; } + // Non-existent filehandle returns EOF + string emitC() override { + return "(%li ? (ungetc(%ri, VL_CVT_I_FP(%li)) >= 0 ? 0 : -1) : -1)"; + } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return widthInstrs() * 64; } + bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering + AstNode* filep() const { return lhsp(); } + AstNode* charp() const { return rhsp(); } +}; +class AstGetcN final : public AstNodeBiop { + // Verilog string.getc() +public: + AstGetcN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_GetcN(fl, lhsp, rhsp) { + dtypeSetBitSized(8, VSigning::UNSIGNED); + } + ASTGEN_MEMBERS_GetcN; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstGetcN(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opGetcN(lhs, rhs); + } + string name() const override { return "getc"; } + string emitVerilog() override { return "%k(%l.getc(%r))"; } + string emitC() override { return "VL_GETC_N(%li,%ri)"; } + string emitSimpleOperator() override { return ""; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } +}; +class AstGetcRefN final : public AstNodeBiop { + // Verilog string[#] on the left-hand-side of assignment + // Spec says is of type byte (not string of single character) +public: + AstGetcRefN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_GetcRefN(fl, lhsp, rhsp) { + dtypeSetBitSized(8, VSigning::UNSIGNED); + } + ASTGEN_MEMBERS_GetcRefN; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstGetcRefN(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + V3ERROR_NA; + } + string emitVerilog() override { return "%k%l[%r]"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { return ""; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } +}; +class AstGt final : public AstNodeBiop { +public: + AstGt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Gt(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_Gt; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstGt(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opGt(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f> %r)"; } + string emitC() override { return "VL_GT_%lq(%lW, %P, %li, %ri)"; } + string emitSimpleOperator() override { return ">"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } +}; +class AstGtD final : public AstNodeBiop { +public: + AstGtD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_GtD(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_GtD; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstGtD(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opGtD(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f> %r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { return ">"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_DBL; } + bool doubleFlavor() const override { return true; } +}; +class AstGtN final : public AstNodeBiop { +public: + AstGtN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_GtN(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_GtN; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstGtN(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opGtN(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f> %r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { return ">"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_STR; } + bool stringFlavor() const override { return true; } +}; +class AstGtS final : public AstNodeBiop { +public: + AstGtS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_GtS(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_GtS; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstGtS(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opGtS(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f> %r)"; } + string emitC() override { return "VL_GTS_%nq%lq%rq(%lw, %P, %li, %ri)"; } + string emitSimpleOperator() override { return ""; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + bool signedFlavor() const override { return true; } +}; +class AstGte final : public AstNodeBiop { +public: + AstGte(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Gte(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_Gte; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstGte(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opGte(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f>= %r)"; } + string emitC() override { return "VL_GTE_%lq(%lW, %P, %li, %ri)"; } + string emitSimpleOperator() override { return ">="; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } +}; +class AstGteD final : public AstNodeBiop { +public: + AstGteD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_GteD(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_GteD; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstGteD(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opGteD(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f>= %r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { return ">="; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_DBL; } + bool doubleFlavor() const override { return true; } +}; +class AstGteN final : public AstNodeBiop { +public: + AstGteN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_GteN(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_GteN; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstGteN(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opGteN(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f>= %r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { return ">="; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_STR; } + bool stringFlavor() const override { return true; } +}; +class AstGteS final : public AstNodeBiop { +public: + AstGteS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_GteS(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_GteS; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstGteS(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opGteS(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f>= %r)"; } + string emitC() override { return "VL_GTES_%nq%lq%rq(%lw, %P, %li, %ri)"; } + string emitSimpleOperator() override { return ""; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + bool signedFlavor() const override { return true; } +}; +class AstLogAnd final : public AstNodeBiop { +public: + AstLogAnd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_LogAnd(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_LogAnd; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLogAnd(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLogAnd(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f&& %r)"; } + string emitC() override { return "VL_LOGAND_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + string emitSimpleOperator() override { return "&&"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } +}; +class AstLogIf final : public AstNodeBiop { +public: + AstLogIf(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_LogIf(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_LogIf; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLogIf(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLogIf(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f-> %r)"; } + string emitC() override { return "VL_LOGIF_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + string emitSimpleOperator() override { return "->"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } +}; +class AstLogOr final : public AstNodeBiop { + // LOGOR with optional side effects + // Side effects currently used in some V3Width code + // TBD if this concept is generally adopted for side-effect tracking + // versus V3Const tracking it itself + bool m_sideEffect = false; // Has side effect, relies on short-circuiting +public: + AstLogOr(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_LogOr(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_LogOr; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLogOr(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLogOr(lhs, rhs); + } + bool same(const AstNode* samep) const override { + const AstLogOr* const sp = static_cast(samep); + return m_sideEffect == sp->m_sideEffect; + } + void dump(std::ostream& str = std::cout) const override; + string emitVerilog() override { return "%k(%l %f|| %r)"; } + string emitC() override { return "VL_LOGOR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + string emitSimpleOperator() override { return "||"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } + bool isPure() const override { return !m_sideEffect; } + void sideEffect(bool flag) { m_sideEffect = flag; } + bool sideEffect() const { return m_sideEffect; } +}; +class AstLt final : public AstNodeBiop { +public: + AstLt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Lt(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_Lt; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLt(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLt(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f< %r)"; } + string emitC() override { return "VL_LT_%lq(%lW, %P, %li, %ri)"; } + string emitSimpleOperator() override { return "<"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } +}; +class AstLtD final : public AstNodeBiop { +public: + AstLtD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_LtD(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_LtD; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLtD(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLtD(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f< %r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { return "<"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_DBL; } + bool doubleFlavor() const override { return true; } +}; +class AstLtN final : public AstNodeBiop { +public: + AstLtN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_LtN(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_LtN; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLtN(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLtN(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f< %r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { return "<"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_STR; } + bool stringFlavor() const override { return true; } +}; +class AstLtS final : public AstNodeBiop { +public: + AstLtS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_LtS(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_LtS; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLtS(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLtS(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f< %r)"; } + string emitC() override { return "VL_LTS_%nq%lq%rq(%lw, %P, %li, %ri)"; } + string emitSimpleOperator() override { return ""; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + bool signedFlavor() const override { return true; } +}; +class AstLte final : public AstNodeBiop { +public: + AstLte(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Lte(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_Lte; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLte(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLte(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f<= %r)"; } + string emitC() override { return "VL_LTE_%lq(%lW, %P, %li, %ri)"; } + string emitSimpleOperator() override { return "<="; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } +}; +class AstLteD final : public AstNodeBiop { +public: + AstLteD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_LteD(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_LteD; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLteD(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLteD(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f<= %r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { return "<="; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_DBL; } + bool doubleFlavor() const override { return true; } +}; +class AstLteN final : public AstNodeBiop { +public: + AstLteN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_LteN(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_LteN; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLteN(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLteN(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f<= %r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { return "<="; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_STR; } + bool stringFlavor() const override { return true; } +}; +class AstLteS final : public AstNodeBiop { +public: + AstLteS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_LteS(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_LteS; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLteS(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLteS(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f<= %r)"; } + string emitC() override { return "VL_LTES_%nq%lq%rq(%lw, %P, %li, %ri)"; } + string emitSimpleOperator() override { return ""; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + bool signedFlavor() const override { return true; } +}; +class AstModDiv final : public AstNodeBiop { +public: + AstModDiv(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_ModDiv(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTGEN_MEMBERS_ModDiv; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstModDiv(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opModDiv(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f%% %r)"; } + string emitC() override { return "VL_MODDIV_%nq%lq%rq(%lw, %P, %li, %ri)"; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return true; } + bool sizeMattersRhs() const override { return true; } + int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_DIV; } +}; +class AstModDivS final : public AstNodeBiop { +public: + AstModDivS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_ModDivS(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTGEN_MEMBERS_ModDivS; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstModDivS(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opModDivS(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f%% %r)"; } + string emitC() override { return "VL_MODDIVS_%nq%lq%rq(%lw, %P, %li, %ri)"; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return true; } + bool sizeMattersRhs() const override { return true; } + int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_DIV; } + bool signedFlavor() const override { return true; } +}; +class AstNeqWild final : public AstNodeBiop { +public: + AstNeqWild(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_NeqWild(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_NeqWild; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstNeqWild(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opWildNeq(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f!=? %r)"; } + string emitC() override { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; } + string emitSimpleOperator() override { return "!="; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } +}; +class AstPow final : public AstNodeBiop { +public: + AstPow(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Pow(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTGEN_MEMBERS_Pow; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstPow(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opPow(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f** %r)"; } + string emitC() override { return "VL_POW_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + bool emitCheckMaxWords() override { return true; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return true; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL * 10; } +}; +class AstPowD final : public AstNodeBiop { +public: + AstPowD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_PowD(fl, lhsp, rhsp) { + dtypeSetDouble(); + } + ASTGEN_MEMBERS_PowD; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstPowD(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opPowD(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f** %r)"; } + string emitC() override { return "pow(%li,%ri)"; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_DBL_DIV * 5; } + bool doubleFlavor() const override { return true; } +}; +class AstPowSS final : public AstNodeBiop { +public: + AstPowSS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_PowSS(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTGEN_MEMBERS_PowSS; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstPowSS(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opPowSS(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f** %r)"; } + string emitC() override { return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 1,1)"; } + bool emitCheckMaxWords() override { return true; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return true; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL * 10; } + bool signedFlavor() const override { return true; } +}; +class AstPowSU final : public AstNodeBiop { +public: + AstPowSU(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_PowSU(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTGEN_MEMBERS_PowSU; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstPowSU(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opPowSU(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f** %r)"; } + string emitC() override { return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 1,0)"; } + bool emitCheckMaxWords() override { return true; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return true; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL * 10; } + bool signedFlavor() const override { return true; } +}; +class AstPowUS final : public AstNodeBiop { +public: + AstPowUS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_PowUS(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTGEN_MEMBERS_PowUS; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstPowUS(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opPowUS(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f** %r)"; } + string emitC() override { return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 0,1)"; } + bool emitCheckMaxWords() override { return true; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return true; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL * 10; } + bool signedFlavor() const override { return true; } +}; +class AstReplicate final : public AstNodeBiop { + // Also used as a "Uniop" flavor of Concat, e.g. "{a}" + // Verilog {rhs{lhs}} - Note rhsp() is the replicate value, not the lhsp() + // @astgen alias op1 := srcp + // @astgen alias op2 := countp +public: + AstReplicate(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Replicate(fl, lhsp, rhsp) { + if (lhsp) { + if (const AstConst* const constp = VN_CAST(rhsp, Const)) { + dtypeSetLogicSized(lhsp->width() * constp->toUInt(), VSigning::UNSIGNED); + } + } + } + AstReplicate(FileLine* fl, AstNode* lhsp, uint32_t repCount) + : AstReplicate(fl, lhsp, new AstConst(fl, repCount)) {} + ASTGEN_MEMBERS_Replicate; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstReplicate(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opRepl(lhs, rhs); + } + string emitVerilog() override { return "%f{%r{%k%l}}"; } + string emitC() override { return "VL_REPLICATE_%nq%lq%rq(%lw, %P, %li, %ri)"; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return widthInstrs() * 2; } +}; +class AstReplicateN final : public AstNodeBiop { + // String replicate +public: + AstReplicateN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_ReplicateN(fl, lhsp, rhsp) { + dtypeSetString(); + } + AstReplicateN(FileLine* fl, AstNode* lhsp, uint32_t repCount) + : AstReplicateN(fl, lhsp, new AstConst(fl, repCount)) {} + ASTGEN_MEMBERS_ReplicateN; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstReplicateN(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opReplN(lhs, rhs); + } + string emitVerilog() override { return "%f{%r{%k%l}}"; } + string emitC() override { return "VL_REPLICATEN_NN%rq(%li, %ri)"; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return widthInstrs() * 2; } + bool stringFlavor() const override { return true; } +}; +class AstShiftL final : public AstNodeBiop { +public: + AstShiftL(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) + : ASTGEN_SUPER_ShiftL(fl, lhsp, rhsp) { + if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); + } + ASTGEN_MEMBERS_ShiftL; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstShiftL(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opShiftL(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f<< %r)"; } + string emitC() override { return "VL_SHIFTL_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + string emitSimpleOperator() override { + return (rhsp()->isWide() || rhsp()->isQuad()) ? "" : "<<"; + } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return true; } + bool sizeMattersRhs() const override { return false; } +}; +class AstShiftR final : public AstNodeBiop { +public: + AstShiftR(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) + : ASTGEN_SUPER_ShiftR(fl, lhsp, rhsp) { + if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); + } + ASTGEN_MEMBERS_ShiftR; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstShiftR(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opShiftR(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f>> %r)"; } + string emitC() override { return "VL_SHIFTR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + string emitSimpleOperator() override { + return (rhsp()->isWide() || rhsp()->isQuad()) ? "" : ">>"; + } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + // LHS size might be > output size, so don't want to force size + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } +}; +class AstShiftRS final : public AstNodeBiop { + // Shift right with sign extension, >>> operator + // Output data type's width determines which bit is used for sign extension +public: + AstShiftRS(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) + : ASTGEN_SUPER_ShiftRS(fl, lhsp, rhsp) { + // Important that widthMin be correct, as opExtend requires it after V3Expand + if (setwidth) dtypeSetLogicSized(setwidth, VSigning::SIGNED); + } + ASTGEN_MEMBERS_ShiftRS; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstShiftRS(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opShiftRS(lhs, rhs, lhsp()->widthMinV()); + } + string emitVerilog() override { return "%k(%l %f>>> %r)"; } + string emitC() override { return "VL_SHIFTRS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + string emitSimpleOperator() override { return ""; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + bool signedFlavor() const override { return true; } +}; +class AstSub final : public AstNodeBiop { +public: + AstSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Sub(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTGEN_MEMBERS_Sub; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstSub(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opSub(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f- %r)"; } + string emitC() override { return "VL_SUB_%lq(%lW, %P, %li, %ri)"; } + string emitSimpleOperator() override { return "-"; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return true; } + bool sizeMattersRhs() const override { return true; } +}; +class AstSubD final : public AstNodeBiop { +public: + AstSubD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_SubD(fl, lhsp, rhsp) { + dtypeSetDouble(); + } + ASTGEN_MEMBERS_SubD; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstSubD(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opSubD(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f- %r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { return "-"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_DBL; } + bool doubleFlavor() const override { return true; } +}; +class AstURandomRange final : public AstNodeBiop { + // $urandom_range +public: + explicit AstURandomRange(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_URandomRange(fl, lhsp, rhsp) { + dtypeSetUInt32(); // Says IEEE + } + ASTGEN_MEMBERS_URandomRange; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstURandomRange(fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + V3ERROR_NA; + } + string emitVerilog() override { return "%f$urandom_range(%l, %r)"; } + string emitC() override { return "VL_URANDOM_RANGE_%nq(%li, %ri)"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + int instrCount() const override { return INSTR_COUNT_PLI; } +}; + +// === AstNodeBiCom === +class AstEq final : public AstNodeBiCom { +public: + AstEq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Eq(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_Eq; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstEq(this->fileline(), lhsp, rhsp); + } + static AstNodeBiop* newTyped(FileLine* fl, AstNode* lhsp, + AstNode* rhsp); // Return AstEq/AstEqD + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opEq(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f== %r)"; } + string emitC() override { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; } + string emitSimpleOperator() override { return "=="; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } +}; +class AstEqCase final : public AstNodeBiCom { +public: + AstEqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_EqCase(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_EqCase; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstEqCase(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opCaseEq(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f=== %r)"; } + string emitC() override { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; } + string emitSimpleOperator() override { return "=="; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } +}; +class AstEqD final : public AstNodeBiCom { +public: + AstEqD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_EqD(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_EqD; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstEqD(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opEqD(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f== %r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { return "=="; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_DBL; } + bool doubleFlavor() const override { return true; } +}; +class AstEqN final : public AstNodeBiCom { +public: + AstEqN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_EqN(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_EqN; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstEqN(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opEqN(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f== %r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { return "=="; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_STR; } + bool stringFlavor() const override { return true; } +}; +class AstLogEq final : public AstNodeBiCom { +public: + AstLogEq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_LogEq(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_LogEq; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstLogEq(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opLogEq(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f<-> %r)"; } + string emitC() override { return "VL_LOGEQ_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + string emitSimpleOperator() override { return "<->"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } +}; +class AstNeq final : public AstNodeBiCom { +public: + AstNeq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Neq(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_Neq; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstNeq(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opNeq(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f!= %r)"; } + string emitC() override { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; } + string emitSimpleOperator() override { return "!="; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } +}; +class AstNeqCase final : public AstNodeBiCom { +public: + AstNeqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_NeqCase(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_NeqCase; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstNeqCase(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opCaseNeq(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f!== %r)"; } + string emitC() override { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; } + string emitSimpleOperator() override { return "!="; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } +}; +class AstNeqD final : public AstNodeBiCom { +public: + AstNeqD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_NeqD(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_NeqD; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstNeqD(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opNeqD(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f!= %r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { return "!="; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_DBL; } + bool doubleFlavor() const override { return true; } +}; +class AstNeqN final : public AstNodeBiCom { +public: + AstNeqN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_NeqN(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_NeqN; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstNeqN(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opNeqN(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f!= %r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { return "!="; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_STR; } + bool stringFlavor() const override { return true; } +}; + +// === AstNodeBiComAsv === +class AstAdd final : public AstNodeBiComAsv { +public: + AstAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Add(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTGEN_MEMBERS_Add; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAdd(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opAdd(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f+ %r)"; } + string emitC() override { return "VL_ADD_%lq(%lW, %P, %li, %ri)"; } + string emitSimpleOperator() override { return "+"; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return true; } + bool sizeMattersRhs() const override { return true; } +}; +class AstAddD final : public AstNodeBiComAsv { +public: + AstAddD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_AddD(fl, lhsp, rhsp) { + dtypeSetDouble(); + } + ASTGEN_MEMBERS_AddD; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAddD(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opAddD(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f+ %r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { return "+"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_DBL; } + bool doubleFlavor() const override { return true; } +}; +class AstAnd final : public AstNodeBiComAsv { +public: + AstAnd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_And(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTGEN_MEMBERS_And; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAnd(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opAnd(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f& %r)"; } + string emitC() override { return "VL_AND_%lq(%lW, %P, %li, %ri)"; } + string emitSimpleOperator() override { return "&"; } + bool cleanOut() const override { V3ERROR_NA_RETURN(false); } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } +}; +class AstMul final : public AstNodeBiComAsv { +public: + AstMul(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Mul(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTGEN_MEMBERS_Mul; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstMul(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opMul(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f* %r)"; } + string emitC() override { return "VL_MUL_%lq(%lW, %P, %li, %ri)"; } + string emitSimpleOperator() override { return "*"; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return true; } + bool sizeMattersRhs() const override { return true; } + int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL; } +}; +class AstMulD final : public AstNodeBiComAsv { +public: + AstMulD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_MulD(fl, lhsp, rhsp) { + dtypeSetDouble(); + } + ASTGEN_MEMBERS_MulD; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstMulD(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opMulD(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f* %r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { return "*"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return true; } + bool sizeMattersRhs() const override { return true; } + int instrCount() const override { return INSTR_COUNT_DBL; } + bool doubleFlavor() const override { return true; } +}; +class AstMulS final : public AstNodeBiComAsv { +public: + AstMulS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_MulS(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTGEN_MEMBERS_MulS; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstMulS(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opMulS(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f* %r)"; } + string emitC() override { return "VL_MULS_%nq%lq%rq(%lw, %P, %li, %ri)"; } + string emitSimpleOperator() override { return ""; } + bool emitCheckMaxWords() override { return true; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return true; } + bool sizeMattersRhs() const override { return true; } + int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL; } + bool signedFlavor() const override { return true; } +}; +class AstOr final : public AstNodeBiComAsv { +public: + AstOr(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Or(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTGEN_MEMBERS_Or; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstOr(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opOr(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f| %r)"; } + string emitC() override { return "VL_OR_%lq(%lW, %P, %li, %ri)"; } + string emitSimpleOperator() override { return "|"; } + bool cleanOut() const override { V3ERROR_NA_RETURN(false); } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } +}; +class AstXor final : public AstNodeBiComAsv { +public: + AstXor(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Xor(fl, lhsp, rhsp) { + dtypeFrom(lhsp); + } + ASTGEN_MEMBERS_Xor; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstXor(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opXor(lhs, rhs); + } + string emitVerilog() override { return "%k(%l %f^ %r)"; } + string emitC() override { return "VL_XOR_%lq(%lW, %P, %li, %ri)"; } + string emitSimpleOperator() override { return "^"; } + bool cleanOut() const override { return false; } // Lclean && Rclean + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } +}; + +// === AstNodeSel === +class AstArraySel final : public AstNodeSel { + // Parents: math|stmt + // Children: varref|arraysel, math +private: + void init(AstNode* fromp) { + if (fromp && VN_IS(fromp->dtypep()->skipRefp(), NodeArrayDType)) { + // Strip off array to find what array references + dtypeFrom(VN_AS(fromp->dtypep()->skipRefp(), NodeArrayDType)->subDTypep()); + } + } + +public: + AstArraySel(FileLine* fl, AstNode* fromp, AstNode* bitp) + : ASTGEN_SUPER_ArraySel(fl, fromp, bitp) { + init(fromp); + } + AstArraySel(FileLine* fl, AstNode* fromp, int bit) + : ASTGEN_SUPER_ArraySel(fl, fromp, new AstConst(fl, bit)) { + init(fromp); + } + ASTGEN_MEMBERS_ArraySel; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstArraySel(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + V3ERROR_NA; /* How can from be a const? */ + } + string emitVerilog() override { return "%k(%l%f[%r])"; } + string emitC() override { return "%li%k[%ri]"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + bool isGateOptimizable() const override { return true; } // esp for V3Const::ifSameAssign + bool isPredictOptimizable() const override { return true; } + bool same(const AstNode* /*samep*/) const override { return true; } + int instrCount() const override { return widthInstrs(); } + // Special operators + // Return base var (or const) nodep dereferences + static AstNode* baseFromp(AstNode* nodep, bool overMembers); +}; +class AstAssocSel final : public AstNodeSel { + // Parents: math|stmt + // Children: varref|arraysel, math +private: + void init(AstNode* fromp) { + if (fromp && VN_IS(fromp->dtypep()->skipRefp(), AssocArrayDType)) { + // Strip off array to find what array references + dtypeFrom(VN_AS(fromp->dtypep()->skipRefp(), AssocArrayDType)->subDTypep()); + } + } + +public: + AstAssocSel(FileLine* fl, AstNode* fromp, AstNode* bitp) + : ASTGEN_SUPER_AssocSel(fl, fromp, bitp) { + init(fromp); + } + ASTGEN_MEMBERS_AssocSel; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAssocSel(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + V3ERROR_NA; + } + string emitVerilog() override { return "%k(%l%f[%r])"; } + string emitC() override { return "%li%k[%ri]"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + bool isGateOptimizable() const override { return true; } // esp for V3Const::ifSameAssign + bool isPredictOptimizable() const override { return false; } + bool same(const AstNode* /*samep*/) const override { return true; } + int instrCount() const override { return widthInstrs(); } +}; +class AstWildcardSel final : public AstNodeSel { + // Parents: math|stmt + // Children: varref|arraysel, math +private: + void init(AstNode* fromp) { + if (fromp && VN_IS(fromp->dtypep()->skipRefp(), WildcardArrayDType)) { + // Strip off array to find what array references + dtypeFrom(VN_AS(fromp->dtypep()->skipRefp(), WildcardArrayDType)->subDTypep()); + } + } + +public: + AstWildcardSel(FileLine* fl, AstNode* fromp, AstNode* bitp) + : ASTGEN_SUPER_WildcardSel(fl, fromp, bitp) { + init(fromp); + } + ASTGEN_MEMBERS_WildcardSel; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstWildcardSel{this->fileline(), lhsp, rhsp}; + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + V3ERROR_NA; + } + string emitVerilog() override { return "%k(%l%f[%r])"; } + string emitC() override { return "%li%k[%ri]"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + bool isGateOptimizable() const override { return true; } // esp for V3Const::ifSameAssign + bool isPredictOptimizable() const override { return false; } + bool same(const AstNode* /*samep*/) const override { return true; } + int instrCount() const override { return widthInstrs(); } +}; +class AstWordSel final : public AstNodeSel { + // Select a single word from a multi-word wide value +public: + AstWordSel(FileLine* fl, AstNode* fromp, AstNode* bitp) + : ASTGEN_SUPER_WordSel(fl, fromp, bitp) { + dtypeSetUInt32(); // Always used on WData arrays so returns edata size + } + ASTGEN_MEMBERS_WordSel; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstWordSel(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit) override { + V3ERROR_NA; + } + string emitVerilog() override { return "%k(%l%f[%r])"; } + string emitC() override { + return "%li[%ri]"; + } // Not %k, as usually it's a small constant rhsp + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; + +// === AstNodeStream === +class AstStreamL final : public AstNodeStream { + // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() +public: + AstStreamL(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_StreamL(fl, lhsp, rhsp) {} + ASTGEN_MEMBERS_StreamL; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstStreamL(this->fileline(), lhsp, rhsp); + } + string emitVerilog() override { return "%f{ << %r %k{%l} }"; } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opStreamL(lhs, rhs); + } + string emitC() override { return "VL_STREAML_%nq%lq%rq(%lw, %P, %li, %ri)"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool sizeMattersLhs() const override { return true; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return widthInstrs() * 2; } +}; +class AstStreamR final : public AstNodeStream { + // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() +public: + AstStreamR(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_StreamR(fl, lhsp, rhsp) {} + ASTGEN_MEMBERS_StreamR; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstStreamR(this->fileline(), lhsp, rhsp); + } + string emitVerilog() override { return "%f{ >> %r %k{%l} }"; } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.opAssign(lhs); + } + string emitC() override { return isWide() ? "VL_ASSIGN_W(%nw, %P, %li)" : "%li"; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return true; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return widthInstrs() * 2; } +}; + +// === AstNodeSystemBiop === +class AstAtan2D final : public AstNodeSystemBiop { +public: + AstAtan2D(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Atan2D(fl, lhsp, rhsp) {} + ASTGEN_MEMBERS_Atan2D; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAtan2D(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.setDouble(std::atan2(lhs.toDouble(), rhs.toDouble())); + } + string emitVerilog() override { return "%f$atan2(%l,%r)"; } + string emitC() override { return "atan2(%li,%ri)"; } +}; +class AstHypotD final : public AstNodeSystemBiop { +public: + AstHypotD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_HypotD(fl, lhsp, rhsp) {} + ASTGEN_MEMBERS_HypotD; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstHypotD(this->fileline(), lhsp, rhsp); + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + out.setDouble(std::hypot(lhs.toDouble(), rhs.toDouble())); + } + string emitVerilog() override { return "%f$hypot(%l,%r)"; } + string emitC() override { return "hypot(%li,%ri)"; } +}; + +// === AstNodeQuadop === +class AstCountBits final : public AstNodeQuadop { + // Number of bits set in vector +public: + AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p) + : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl1p->cloneTree(false), + ctrl1p->cloneTree(false)) {} + AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p, AstNode* ctrl2p) + : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl2p->cloneTree(false)) {} + AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p, AstNode* ctrl2p, AstNode* ctrl3p) + : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl3p) {} + ASTGEN_MEMBERS_CountBits; + void numberOperate(V3Number& out, const V3Number& expr, const V3Number& ctrl1, + const V3Number& ctrl2, const V3Number& ctrl3) override { + out.opCountBits(expr, ctrl1, ctrl2, ctrl3); + } + string emitVerilog() override { return "%f$countbits(%l, %r, %f, %o)"; } + string emitC() override { return ""; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool cleanThs() const override { return true; } + bool cleanFhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + bool sizeMattersThs() const override { return false; } + bool sizeMattersFhs() const override { return false; } + int instrCount() const override { return widthInstrs() * 16; } +}; + +// === AstNodeTermop === +class AstTime final : public AstNodeTermop { + VTimescale m_timeunit; // Parent module time unit +public: + AstTime(FileLine* fl, const VTimescale& timeunit) + : ASTGEN_SUPER_Time(fl) + , m_timeunit{timeunit} { + dtypeSetUInt64(); + } + ASTGEN_MEMBERS_Time; + string emitVerilog() override { return "%f$time"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + int instrCount() const override { return INSTR_COUNT_TIME; } + bool same(const AstNode* /*samep*/) const override { return true; } + void dump(std::ostream& str = std::cout) const override; + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } +}; +class AstTimeD final : public AstNodeTermop { + VTimescale m_timeunit; // Parent module time unit +public: + AstTimeD(FileLine* fl, const VTimescale& timeunit) + : ASTGEN_SUPER_TimeD(fl) + , m_timeunit{timeunit} { + dtypeSetDouble(); + } + ASTGEN_MEMBERS_TimeD; + string emitVerilog() override { return "%f$realtime"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + int instrCount() const override { return INSTR_COUNT_TIME; } + bool same(const AstNode* /*samep*/) const override { return true; } + void dump(std::ostream& str = std::cout) const override; + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } +}; + +// === AstNodeTriop === +class AstPostAdd final : public AstNodeTriop { + // Post-increment/add + // Parents: MATH + // Children: lhsp: AstConst (1) as currently support only ++ not += + // Children: rhsp: tree with AstVarRef that is value to read before operation + // Children: thsp: tree with AstVarRef LValue that is stored after operation +public: + AstPostAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) + : ASTGEN_SUPER_PostAdd(fl, lhsp, rhsp, thsp) {} + ASTGEN_MEMBERS_PostAdd; + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) override { + V3ERROR_NA; // Need to modify lhs + } + string emitVerilog() override { return "%k(%r++)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool cleanThs() const override { return false; } + bool sizeMattersLhs() const override { return true; } + bool sizeMattersRhs() const override { return true; } + bool sizeMattersThs() const override { return true; } +}; +class AstPostSub final : public AstNodeTriop { + // Post-decrement/subtract + // Parents: MATH + // Children: lhsp: AstConst (1) as currently support only -- not -= + // Children: rhsp: tree with AstVarRef that is value to read before operation + // Children: thsp: tree with AstVarRef LValue that is stored after operation +public: + AstPostSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) + : ASTGEN_SUPER_PostSub(fl, lhsp, rhsp, thsp) {} + ASTGEN_MEMBERS_PostSub; + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) override { + V3ERROR_NA; // Need to modify lhs + } + string emitVerilog() override { return "%k(%r--)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool cleanThs() const override { return false; } + bool sizeMattersLhs() const override { return true; } + bool sizeMattersRhs() const override { return true; } + bool sizeMattersThs() const override { return true; } +}; +class AstPreAdd final : public AstNodeTriop { + // Pre-increment/add + // Parents: MATH + // Children: lhsp: AstConst (1) as currently support only ++ not += + // Children: rhsp: tree with AstVarRef that is value to read before operation + // Children: thsp: tree with AstVarRef LValue that is stored after operation +public: + AstPreAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) + : ASTGEN_SUPER_PreAdd(fl, lhsp, rhsp, thsp) {} + ASTGEN_MEMBERS_PreAdd; + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) override { + V3ERROR_NA; // Need to modify lhs + } + string emitVerilog() override { return "%k(++%r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool cleanThs() const override { return false; } + bool sizeMattersLhs() const override { return true; } + bool sizeMattersRhs() const override { return true; } + bool sizeMattersThs() const override { return true; } +}; +class AstPreSub final : public AstNodeTriop { + // Pre-decrement/subtract + // Parents: MATH + // Children: lhsp: AstConst (1) as currently support only -- not -= + // Children: rhsp: tree with AstVarRef that is value to read before operation + // Children: thsp: tree with AstVarRef LValue that is stored after operation +public: + AstPreSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) + : ASTGEN_SUPER_PreSub(fl, lhsp, rhsp, thsp) {} + ASTGEN_MEMBERS_PreSub; + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) override { + V3ERROR_NA; // Need to modify lhs + } + string emitVerilog() override { return "%k(--%r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool cleanThs() const override { return false; } + bool sizeMattersLhs() const override { return true; } + bool sizeMattersRhs() const override { return true; } + bool sizeMattersThs() const override { return true; } +}; +class AstPutcN final : public AstNodeTriop { + // Verilog string.putc() +public: + AstPutcN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* ths) + : ASTGEN_SUPER_PutcN(fl, lhsp, rhsp, ths) { + dtypeSetString(); + } + ASTGEN_MEMBERS_PutcN; + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) override { + out.opPutcN(lhs, rhs, ths); + } + string name() const override { return "putc"; } + string emitVerilog() override { return "%k(%l.putc(%r,%t))"; } + string emitC() override { return "VL_PUTC_N(%li,%ri,%ti)"; } + string emitSimpleOperator() override { return ""; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool cleanThs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + bool sizeMattersThs() const override { return false; } +}; +class AstSel final : public AstNodeTriop { + // Multiple bit range extraction + // Parents: math|stmt + // Children: varref|arraysel, math, constant math + // @astgen alias op1 := fromp + // @astgen alias op2 := lsbp + // @astgen alias op3 := widthp +private: + VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid + int m_declElWidth; // If a packed array, the number of bits per element +public: + AstSel(FileLine* fl, AstNode* fromp, AstNode* lsbp, AstNode* widthp) + : ASTGEN_SUPER_Sel(fl, fromp, lsbp, widthp) + , m_declElWidth{1} { + if (VN_IS(widthp, Const)) { + dtypeSetLogicSized(VN_AS(widthp, Const)->toUInt(), VSigning::UNSIGNED); + } + } + AstSel(FileLine* fl, AstNode* fromp, int lsb, int bitwidth) + : ASTGEN_SUPER_Sel(fl, fromp, new AstConst(fl, lsb), new AstConst(fl, bitwidth)) + , m_declElWidth{1} { + dtypeSetLogicSized(bitwidth, VSigning::UNSIGNED); + } + ASTGEN_MEMBERS_Sel; + void dump(std::ostream& str) const override; + void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit, + const V3Number& width) override { + out.opSel(from, bit.toUInt() + width.toUInt() - 1, bit.toUInt()); + } + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { + return widthp()->isOne() ? "VL_BITSEL_%nq%lq%rq%tq(%lw, %P, %li, %ri)" + : isWide() ? "VL_SEL_%nq%lq%rq%tq(%nw,%lw, %P, %li, %ri, %ti)" + : "VL_SEL_%nq%lq%rq%tq(%lw, %P, %li, %ri, %ti)"; + } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool cleanThs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + bool sizeMattersThs() const override { return false; } + bool same(const AstNode*) const override { return true; } + int instrCount() const override { return widthInstrs() * (VN_CAST(lsbp(), Const) ? 3 : 10); } + int widthConst() const { return VN_AS(widthp(), Const)->toSInt(); } + int lsbConst() const { return VN_AS(lsbp(), Const)->toSInt(); } + int msbConst() const { return lsbConst() + widthConst() - 1; } + VNumRange& declRange() { return m_declRange; } + const VNumRange& declRange() const { return m_declRange; } + void declRange(const VNumRange& flag) { m_declRange = flag; } + int declElWidth() const { return m_declElWidth; } + void declElWidth(int flag) { m_declElWidth = flag; } +}; +class AstSliceSel final : public AstNodeTriop { + // Multiple array element extraction + // Parents: math|stmt + // @astgen alias op1 := fromp +private: + VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid +public: + AstSliceSel(FileLine* fl, AstNode* fromp, const VNumRange& declRange) + : ASTGEN_SUPER_SliceSel(fl, fromp, new AstConst(fl, declRange.lo()), + new AstConst(fl, declRange.elements())) + , m_declRange{declRange} {} + ASTGEN_MEMBERS_SliceSel; + void dump(std::ostream& str) const override; + void numberOperate(V3Number& out, const V3Number& from, const V3Number& lo, + const V3Number& width) override { + V3ERROR_NA; + } + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } // Removed before EmitC + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return true; } + bool cleanThs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + bool sizeMattersThs() const override { return false; } + bool same(const AstNode*) const override { return true; } + int instrCount() const override { return 10; } // Removed before matters + // For widthConst()/loConst etc, see declRange().elements() and other VNumRange methods + VNumRange& declRange() { return m_declRange; } + const VNumRange& declRange() const { return m_declRange; } + void declRange(const VNumRange& flag) { m_declRange = flag; } +}; +class AstSubstrN final : public AstNodeTriop { + // Verilog string.substr() +public: + AstSubstrN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* ths) + : ASTGEN_SUPER_SubstrN(fl, lhsp, rhsp, ths) { + dtypeSetString(); + } + ASTGEN_MEMBERS_SubstrN; + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) override { + out.opSubstrN(lhs, rhs, ths); + } + string name() const override { return "substr"; } + string emitVerilog() override { return "%k(%l.substr(%r,%t))"; } + string emitC() override { return "VL_SUBSTR_N(%li,%ri,%ti)"; } + string emitSimpleOperator() override { return ""; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool cleanRhs() const override { return true; } + bool cleanThs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + bool sizeMattersThs() const override { return false; } +}; + +// === AstNodeCond === +class AstCond final : public AstNodeCond { + // Conditional ?: statement + // Parents: MATH + // Children: MATH +public: + AstCond(FileLine* fl, AstNode* condp, AstNode* thenp, AstNode* elsep) + : ASTGEN_SUPER_Cond(fl, condp, thenp, elsep) {} + ASTGEN_MEMBERS_Cond; + AstNode* cloneType(AstNode* condp, AstNode* thenp, AstNode* elsep) override { + return new AstCond(this->fileline(), condp, thenp, elsep); + } +}; +class AstCondBound final : public AstNodeCond { + // Conditional ?: statement, specially made for safety checking of array bounds + // Parents: MATH + // Children: MATH +public: + AstCondBound(FileLine* fl, AstNode* condp, AstNode* thenp, AstNode* elsep) + : ASTGEN_SUPER_CondBound(fl, condp, thenp, elsep) {} + ASTGEN_MEMBERS_CondBound; + AstNode* cloneType(AstNode* condp, AstNode* thenp, AstNode* elsep) override { + return new AstCondBound(this->fileline(), condp, thenp, elsep); + } +}; + +// === AstNodeUniop === +class AstAtoN final : public AstNodeUniop { + // string.atoi(), atobin(), atohex(), atooct(), atoireal() +public: + enum FmtType { ATOI = 10, ATOHEX = 16, ATOOCT = 8, ATOBIN = 2, ATOREAL = -1 }; + +private: + const FmtType m_fmt; // Operation type +public: + AstAtoN(FileLine* fl, AstNode* lhsp, FmtType fmt) + : ASTGEN_SUPER_AtoN(fl, lhsp) + , m_fmt{fmt} { + fmt == ATOREAL ? dtypeSetDouble() : dtypeSetSigned32(); + } + ASTGEN_MEMBERS_AtoN; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAtoN(lhs, m_fmt); } + string name() const override { + switch (m_fmt) { + case ATOI: return "atoi"; + case ATOHEX: return "atohex"; + case ATOOCT: return "atooct"; + case ATOBIN: return "atobin"; + case ATOREAL: return "atoreal"; + default: V3ERROR_NA; + } + } + string emitVerilog() override { return "%l." + name() + "()"; } + string emitC() override { + switch (m_fmt) { + case ATOI: return "VL_ATOI_N(%li, 10)"; + case ATOHEX: return "VL_ATOI_N(%li, 16)"; + case ATOOCT: return "VL_ATOI_N(%li, 8)"; + case ATOBIN: return "VL_ATOI_N(%li, 2)"; + case ATOREAL: return "std::atof(%li.c_str())"; + default: V3ERROR_NA; + } + } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + FmtType format() const { return m_fmt; } +}; +class AstBitsToRealD final : public AstNodeUniop { +public: + AstBitsToRealD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_BitsToRealD(fl, lhsp) { + dtypeSetDouble(); + } + ASTGEN_MEMBERS_BitsToRealD; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opBitsToRealD(lhs); } + string emitVerilog() override { return "%f$bitstoreal(%l)"; } + string emitC() override { return "VL_CVT_D_Q(%li)"; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } // Eliminated before matters + bool sizeMattersLhs() const override { return false; } // Eliminated before matters + int instrCount() const override { return INSTR_COUNT_DBL; } +}; +class AstCCast final : public AstNodeUniop { + // Cast to C-based data type +private: + int m_size; + +public: + AstCCast(FileLine* fl, AstNode* lhsp, int setwidth, int minwidth = -1) + : ASTGEN_SUPER_CCast(fl, lhsp) { + m_size = setwidth; + if (setwidth) { + if (minwidth == -1) minwidth = setwidth; + dtypeSetLogicUnsized(setwidth, minwidth, VSigning::UNSIGNED); + } + } + AstCCast(FileLine* fl, AstNode* lhsp, AstNode* typeFromp) + : ASTGEN_SUPER_CCast(fl, lhsp) { + dtypeFrom(typeFromp); + m_size = width(); + } + ASTGEN_MEMBERS_CCast; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAssign(lhs); } + string emitVerilog() override { return "%f$_CAST(%l)"; } + string emitC() override { return "VL_CAST_%nq%lq(%nw,%lw, %P, %li)"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } // Special cased in V3Cast + bool same(const AstNode* samep) const override { + return size() == static_cast(samep)->size(); + } + void dump(std::ostream& str = std::cout) const override; + // + int size() const { return m_size; } +}; +class AstCLog2 final : public AstNodeUniop { +public: + AstCLog2(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_CLog2(fl, lhsp) { + dtypeSetSigned32(); + } + ASTGEN_MEMBERS_CLog2; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opCLog2(lhs); } + string emitVerilog() override { return "%f$clog2(%l)"; } + string emitC() override { return "VL_CLOG2_%lq(%lW, %P, %li)"; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + int instrCount() const override { return widthInstrs() * 16; } +}; +class AstCountOnes final : public AstNodeUniop { + // Number of bits set in vector +public: + AstCountOnes(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_CountOnes(fl, lhsp) {} + ASTGEN_MEMBERS_CountOnes; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opCountOnes(lhs); } + string emitVerilog() override { return "%f$countones(%l)"; } + string emitC() override { return "VL_COUNTONES_%lq(%lW, %P, %li)"; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + int instrCount() const override { return widthInstrs() * 16; } +}; +class AstCvtPackString final : public AstNodeUniop { + // Convert to Verilator Packed String (aka verilog "string") +public: + AstCvtPackString(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_CvtPackString(fl, lhsp) { + dtypeSetString(); + } + ASTGEN_MEMBERS_CvtPackString; + void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } + string emitVerilog() override { return "%f$_CAST(%l)"; } + string emitC() override { return "VL_CVT_PACK_STR_N%lq(%lW, %li)"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstExtend final : public AstNodeUniop { + // Expand a value into a wider entity by 0 extension. Width is implied from nodep->width() +public: + AstExtend(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_Extend(fl, lhsp) {} + AstExtend(FileLine* fl, AstNode* lhsp, int width) + : ASTGEN_SUPER_Extend(fl, lhsp) { + dtypeSetLogicSized(width, VSigning::UNSIGNED); + } + ASTGEN_MEMBERS_Extend; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAssign(lhs); } + string emitVerilog() override { return "%l"; } + string emitC() override { return "VL_EXTEND_%nq%lq(%nw,%lw, %P, %li)"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { + return false; // Because the EXTEND operator self-casts + } + int instrCount() const override { return 0; } +}; +class AstExtendS final : public AstNodeUniop { + // Expand a value into a wider entity by sign extension. Width is implied from nodep->width() +public: + AstExtendS(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_ExtendS(fl, lhsp) {} + AstExtendS(FileLine* fl, AstNode* lhsp, int width) + // Important that widthMin be correct, as opExtend requires it after V3Expand + : ASTGEN_SUPER_ExtendS(fl, lhsp) { + dtypeSetLogicSized(width, VSigning::UNSIGNED); + } + ASTGEN_MEMBERS_ExtendS; + void numberOperate(V3Number& out, const V3Number& lhs) override { + out.opExtendS(lhs, lhsp()->widthMinV()); + } + string emitVerilog() override { return "%l"; } + string emitC() override { return "VL_EXTENDS_%nq%lq(%nw,%lw, %P, %li)"; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { + return false; // Because the EXTEND operator self-casts + } + int instrCount() const override { return 0; } + bool signedFlavor() const override { return true; } +}; +class AstFEof final : public AstNodeUniop { +public: + AstFEof(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_FEof(fl, lhsp) {} + ASTGEN_MEMBERS_FEof; + void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } + string emitVerilog() override { return "%f$feof(%l)"; } + string emitC() override { return "(%li ? feof(VL_CVT_I_FP(%li)) : true)"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + int instrCount() const override { return widthInstrs() * 16; } + bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering + AstNode* filep() const { return lhsp(); } +}; +class AstFGetC final : public AstNodeUniop { +public: + AstFGetC(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_FGetC(fl, lhsp) {} + ASTGEN_MEMBERS_FGetC; + void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } + string emitVerilog() override { return "%f$fgetc(%l)"; } + // Non-existent filehandle returns EOF + string emitC() override { return "(%li ? fgetc(VL_CVT_I_FP(%li)) : -1)"; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + int instrCount() const override { return widthInstrs() * 64; } + bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering + AstNode* filep() const { return lhsp(); } +}; +class AstISToRD final : public AstNodeUniop { + // $itor where lhs is signed +public: + AstISToRD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_ISToRD(fl, lhsp) { + dtypeSetDouble(); + } + ASTGEN_MEMBERS_ISToRD; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opISToRD(lhs); } + string emitVerilog() override { return "%f$itor($signed(%l))"; } + string emitC() override { return "VL_ISTOR_D_%lq(%lw, %li)"; } + bool emitCheckMaxWords() override { return true; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_DBL; } +}; +class AstIToRD final : public AstNodeUniop { + // $itor where lhs is unsigned +public: + AstIToRD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_IToRD(fl, lhsp) { + dtypeSetDouble(); + } + ASTGEN_MEMBERS_IToRD; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opIToRD(lhs); } + string emitVerilog() override { return "%f$itor(%l)"; } + string emitC() override { return "VL_ITOR_D_%lq(%lw, %li)"; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_DBL; } +}; +class AstIsUnbounded final : public AstNodeUniop { + // True if is unmbounded ($) +public: + AstIsUnbounded(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_IsUnbounded(fl, lhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_IsUnbounded; + void numberOperate(V3Number& out, const V3Number&) override { + // Any constant isn't unbounded + out.setZero(); + } + string emitVerilog() override { return "%f$isunbounded(%l)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } +}; +class AstIsUnknown final : public AstNodeUniop { + // True if any unknown bits +public: + AstIsUnknown(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_IsUnknown(fl, lhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_IsUnknown; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opIsUnknown(lhs); } + string emitVerilog() override { return "%f$isunknown(%l)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } +}; +class AstLenN final : public AstNodeUniop { + // Length of a string +public: + AstLenN(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_LenN(fl, lhsp) { + dtypeSetSigned32(); + } + ASTGEN_MEMBERS_LenN; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opLenN(lhs); } + string emitVerilog() override { return "%f(%l)"; } + string emitC() override { return "VL_LEN_IN(%li)"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } +}; +class AstLogNot final : public AstNodeUniop { +public: + AstLogNot(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_LogNot(fl, lhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_LogNot; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opLogNot(lhs); } + string emitVerilog() override { return "%f(! %l)"; } + string emitC() override { return "VL_LOGNOT_%nq%lq(%nw,%lw, %P, %li)"; } + string emitSimpleOperator() override { return "!"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } +}; +class AstNegate final : public AstNodeUniop { +public: + AstNegate(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_Negate(fl, lhsp) { + dtypeFrom(lhsp); + } + ASTGEN_MEMBERS_Negate; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNegate(lhs); } + string emitVerilog() override { return "%f(- %l)"; } + string emitC() override { return "VL_NEGATE_%lq(%lW, %P, %li)"; } + string emitSimpleOperator() override { return "-"; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } + bool sizeMattersLhs() const override { return true; } +}; +class AstNegateD final : public AstNodeUniop { +public: + AstNegateD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_NegateD(fl, lhsp) { + dtypeSetDouble(); + } + ASTGEN_MEMBERS_NegateD; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNegateD(lhs); } + string emitVerilog() override { return "%f(- %l)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { return "-"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_DBL; } + bool doubleFlavor() const override { return true; } +}; +class AstNot final : public AstNodeUniop { +public: + AstNot(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_Not(fl, lhsp) { + dtypeFrom(lhsp); + } + ASTGEN_MEMBERS_Not; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNot(lhs); } + string emitVerilog() override { return "%f(~ %l)"; } + string emitC() override { return "VL_NOT_%lq(%lW, %P, %li)"; } + string emitSimpleOperator() override { return "~"; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } + bool sizeMattersLhs() const override { return true; } +}; +class AstNullCheck final : public AstNodeUniop { + // Return LHS after checking that LHS is non-null + // Children: VarRef or something returning pointer +public: + AstNullCheck(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_NullCheck(fl, lhsp) { + dtypeFrom(lhsp); + } + ASTGEN_MEMBERS_NullCheck; + void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } + int instrCount() const override { return 1; } // Rarely executes + string emitVerilog() override { return "%l"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + bool same(const AstNode* samep) const override { return fileline() == samep->fileline(); } +}; +class AstOneHot final : public AstNodeUniop { + // True if only single bit set in vector +public: + AstOneHot(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_OneHot(fl, lhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_OneHot; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opOneHot(lhs); } + string emitVerilog() override { return "%f$onehot(%l)"; } + string emitC() override { return "VL_ONEHOT_%lq(%lW, %P, %li)"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + int instrCount() const override { return widthInstrs() * 4; } +}; +class AstOneHot0 final : public AstNodeUniop { + // True if only single bit, or no bits set in vector +public: + AstOneHot0(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_OneHot0(fl, lhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_OneHot0; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opOneHot0(lhs); } + string emitVerilog() override { return "%f$onehot0(%l)"; } + string emitC() override { return "VL_ONEHOT0_%lq(%lW, %P, %li)"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + int instrCount() const override { return widthInstrs() * 3; } +}; +class AstRToIRoundS final : public AstNodeUniop { + // Convert real to integer, with arbitrary sized output (not just "integer" format) +public: + AstRToIRoundS(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_RToIRoundS(fl, lhsp) { + dtypeSetSigned32(); + } + ASTGEN_MEMBERS_RToIRoundS; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRToIRoundS(lhs); } + string emitVerilog() override { return "%f$rtoi_rounded(%l)"; } + string emitC() override { + return isWide() ? "VL_RTOIROUND_%nq_D(%nw, %P, %li)" : "VL_RTOIROUND_%nq_D(%li)"; + } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_DBL; } +}; +class AstRToIS final : public AstNodeUniop { + // $rtoi(lhs) +public: + AstRToIS(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_RToIS(fl, lhsp) { + dtypeSetSigned32(); + } + ASTGEN_MEMBERS_RToIS; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRToIS(lhs); } + string emitVerilog() override { return "%f$rtoi(%l)"; } + string emitC() override { return "VL_RTOI_I_D(%li)"; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } // Eliminated before matters + bool sizeMattersLhs() const override { return false; } // Eliminated before matters + int instrCount() const override { return INSTR_COUNT_DBL; } +}; +class AstRealToBits final : public AstNodeUniop { +public: + AstRealToBits(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_RealToBits(fl, lhsp) { + dtypeSetUInt64(); + } + ASTGEN_MEMBERS_RealToBits; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRealToBits(lhs); } + string emitVerilog() override { return "%f$realtobits(%l)"; } + string emitC() override { return "VL_CVT_Q_D(%li)"; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } // Eliminated before matters + bool sizeMattersLhs() const override { return false; } // Eliminated before matters + int instrCount() const override { return INSTR_COUNT_DBL; } +}; +class AstRedAnd final : public AstNodeUniop { +public: + AstRedAnd(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_RedAnd(fl, lhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_RedAnd; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedAnd(lhs); } + string emitVerilog() override { return "%f(& %l)"; } + string emitC() override { return "VL_REDAND_%nq%lq(%lw, %P, %li)"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } +}; +class AstRedOr final : public AstNodeUniop { +public: + AstRedOr(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_RedOr(fl, lhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_RedOr; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedOr(lhs); } + string emitVerilog() override { return "%f(| %l)"; } + string emitC() override { return "VL_REDOR_%lq(%lW, %P, %li)"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } +}; +class AstRedXor final : public AstNodeUniop { +public: + AstRedXor(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_RedXor(fl, lhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_RedXor; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedXor(lhs); } + string emitVerilog() override { return "%f(^ %l)"; } + string emitC() override { return "VL_REDXOR_%lq(%lW, %P, %li)"; } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { + const int w = lhsp()->width(); + return (w != 1 && w != 2 && w != 4 && w != 8 && w != 16); + } + bool sizeMattersLhs() const override { return false; } + int instrCount() const override { return 1 + V3Number::log2b(width()); } +}; +class AstSigned final : public AstNodeUniop { + // $signed(lhs) +public: + AstSigned(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_Signed(fl, lhsp) { + UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, + "not coded to create after dtypes resolved"); + } + ASTGEN_MEMBERS_Signed; + void numberOperate(V3Number& out, const V3Number& lhs) override { + out.opAssign(lhs); + out.isSigned(false); + } + string emitVerilog() override { return "%f$signed(%l)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } // Eliminated before matters + bool sizeMattersLhs() const override { return true; } // Eliminated before matters + int instrCount() const override { return 0; } +}; +class AstTimeImport final : public AstNodeUniop { + // Take a constant that represents a time and needs conversion based on time units + VTimescale m_timeunit; // Parent module time unit +public: + AstTimeImport(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_TimeImport(fl, lhsp) {} + ASTGEN_MEMBERS_TimeImport; + void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } + string emitVerilog() override { return "%l"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + void dump(std::ostream& str = std::cout) const override; + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } +}; +class AstToLowerN final : public AstNodeUniop { + // string.tolower() +public: + AstToLowerN(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_ToLowerN(fl, lhsp) { + dtypeSetString(); + } + ASTGEN_MEMBERS_ToLowerN; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opToLowerN(lhs); } + string emitVerilog() override { return "%l.tolower()"; } + string emitC() override { return "VL_TOLOWER_NN(%li)"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } +}; +class AstToUpperN final : public AstNodeUniop { + // string.toupper() +public: + AstToUpperN(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_ToUpperN(fl, lhsp) { + dtypeSetString(); + } + ASTGEN_MEMBERS_ToUpperN; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opToUpperN(lhs); } + string emitVerilog() override { return "%l.toupper()"; } + string emitC() override { return "VL_TOUPPER_NN(%li)"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } +}; +class AstUnsigned final : public AstNodeUniop { + // $unsigned(lhs) +public: + AstUnsigned(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_Unsigned(fl, lhsp) { + UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, + "not coded to create after dtypes resolved"); + } + ASTGEN_MEMBERS_Unsigned; + void numberOperate(V3Number& out, const V3Number& lhs) override { + out.opAssign(lhs); + out.isSigned(false); + } + string emitVerilog() override { return "%f$unsigned(%l)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return false; } + bool cleanLhs() const override { return false; } // Eliminated before matters + bool sizeMattersLhs() const override { return true; } // Eliminated before matters + int instrCount() const override { return 0; } +}; + +// === AstNodeSystemUniop === +class AstAcosD final : public AstNodeSystemUniop { +public: + AstAcosD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_AcosD(fl, lhsp) {} + ASTGEN_MEMBERS_AcosD; + void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::acos(lhs.toDouble())); + } + string emitVerilog() override { return "%f$acos(%l)"; } + string emitC() override { return "acos(%li)"; } +}; +class AstAcoshD final : public AstNodeSystemUniop { +public: + AstAcoshD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_AcoshD(fl, lhsp) {} + ASTGEN_MEMBERS_AcoshD; + void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::acosh(lhs.toDouble())); + } + string emitVerilog() override { return "%f$acosh(%l)"; } + string emitC() override { return "acosh(%li)"; } +}; +class AstAsinD final : public AstNodeSystemUniop { +public: + AstAsinD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_AsinD(fl, lhsp) {} + ASTGEN_MEMBERS_AsinD; + void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::asin(lhs.toDouble())); + } + string emitVerilog() override { return "%f$asin(%l)"; } + string emitC() override { return "asin(%li)"; } +}; +class AstAsinhD final : public AstNodeSystemUniop { +public: + AstAsinhD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_AsinhD(fl, lhsp) {} + ASTGEN_MEMBERS_AsinhD; + void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::asinh(lhs.toDouble())); + } + string emitVerilog() override { return "%f$asinh(%l)"; } + string emitC() override { return "asinh(%li)"; } +}; +class AstAtanD final : public AstNodeSystemUniop { +public: + AstAtanD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_AtanD(fl, lhsp) {} + ASTGEN_MEMBERS_AtanD; + void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::atan(lhs.toDouble())); + } + string emitVerilog() override { return "%f$atan(%l)"; } + string emitC() override { return "atan(%li)"; } +}; +class AstAtanhD final : public AstNodeSystemUniop { +public: + AstAtanhD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_AtanhD(fl, lhsp) {} + ASTGEN_MEMBERS_AtanhD; + void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::atanh(lhs.toDouble())); + } + string emitVerilog() override { return "%f$atanh(%l)"; } + string emitC() override { return "atanh(%li)"; } +}; +class AstCeilD final : public AstNodeSystemUniop { +public: + AstCeilD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_CeilD(fl, lhsp) {} + ASTGEN_MEMBERS_CeilD; + void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::ceil(lhs.toDouble())); + } + string emitVerilog() override { return "%f$ceil(%l)"; } + string emitC() override { return "ceil(%li)"; } +}; +class AstCosD final : public AstNodeSystemUniop { +public: + AstCosD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_CosD(fl, lhsp) {} + ASTGEN_MEMBERS_CosD; + void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::cos(lhs.toDouble())); + } + string emitVerilog() override { return "%f$cos(%l)"; } + string emitC() override { return "cos(%li)"; } +}; +class AstCoshD final : public AstNodeSystemUniop { +public: + AstCoshD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_CoshD(fl, lhsp) {} + ASTGEN_MEMBERS_CoshD; + void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::cosh(lhs.toDouble())); + } + string emitVerilog() override { return "%f$cosh(%l)"; } + string emitC() override { return "cosh(%li)"; } +}; +class AstExpD final : public AstNodeSystemUniop { +public: + AstExpD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_ExpD(fl, lhsp) {} + ASTGEN_MEMBERS_ExpD; + void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::exp(lhs.toDouble())); + } + string emitVerilog() override { return "%f$exp(%l)"; } + string emitC() override { return "exp(%li)"; } +}; +class AstFloorD final : public AstNodeSystemUniop { +public: + AstFloorD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_FloorD(fl, lhsp) {} + ASTGEN_MEMBERS_FloorD; + void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::floor(lhs.toDouble())); + } + string emitVerilog() override { return "%f$floor(%l)"; } + string emitC() override { return "floor(%li)"; } +}; +class AstLog10D final : public AstNodeSystemUniop { +public: + AstLog10D(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_Log10D(fl, lhsp) {} + ASTGEN_MEMBERS_Log10D; + void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::log10(lhs.toDouble())); + } + string emitVerilog() override { return "%f$log10(%l)"; } + string emitC() override { return "log10(%li)"; } +}; +class AstLogD final : public AstNodeSystemUniop { +public: + AstLogD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_LogD(fl, lhsp) {} + ASTGEN_MEMBERS_LogD; + void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::log(lhs.toDouble())); + } + string emitVerilog() override { return "%f$ln(%l)"; } + string emitC() override { return "log(%li)"; } +}; +class AstSinD final : public AstNodeSystemUniop { +public: + AstSinD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_SinD(fl, lhsp) {} + ASTGEN_MEMBERS_SinD; + void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::sin(lhs.toDouble())); + } + string emitVerilog() override { return "%f$sin(%l)"; } + string emitC() override { return "sin(%li)"; } +}; +class AstSinhD final : public AstNodeSystemUniop { +public: + AstSinhD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_SinhD(fl, lhsp) {} + ASTGEN_MEMBERS_SinhD; + void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::sinh(lhs.toDouble())); + } + string emitVerilog() override { return "%f$sinh(%l)"; } + string emitC() override { return "sinh(%li)"; } +}; +class AstSqrtD final : public AstNodeSystemUniop { +public: + AstSqrtD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_SqrtD(fl, lhsp) {} + ASTGEN_MEMBERS_SqrtD; + void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::sqrt(lhs.toDouble())); + } + string emitVerilog() override { return "%f$sqrt(%l)"; } + string emitC() override { return "sqrt(%li)"; } +}; +class AstTanD final : public AstNodeSystemUniop { +public: + AstTanD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_TanD(fl, lhsp) {} + ASTGEN_MEMBERS_TanD; + void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::tan(lhs.toDouble())); + } + string emitVerilog() override { return "%f$tan(%l)"; } + string emitC() override { return "tan(%li)"; } +}; +class AstTanhD final : public AstNodeSystemUniop { +public: + AstTanhD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_TanhD(fl, lhsp) {} + ASTGEN_MEMBERS_TanhD; + void numberOperate(V3Number& out, const V3Number& lhs) override { + out.setDouble(std::tanh(lhs.toDouble())); + } + string emitVerilog() override { return "%f$tanh(%l)"; } + string emitC() override { return "tanh(%li)"; } +}; + +// === AstNodeVarRef === +class AstVarRef final : public AstNodeVarRef { + // A reference to a variable (lvalue or rvalue) +public: + AstVarRef(FileLine* fl, const string& name, const VAccess& access) + : ASTGEN_SUPER_VarRef(fl, name, nullptr, access) {} + // This form only allowed post-link because output/wire compression may + // lead to deletion of AstVar's + inline AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access); + // This form only allowed post-link (see above) + inline AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access); + ASTGEN_MEMBERS_VarRef; + void dump(std::ostream& str) const override; + bool same(const AstNode* samep) const override; + inline bool same(const AstVarRef* samep) const; + inline bool sameNoLvalue(AstVarRef* samep) const; + int instrCount() const override { + return widthInstrs() * (access().isReadOrRW() ? INSTR_COUNT_LD : 1); + } + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } +}; +class AstVarXRef final : public AstNodeVarRef { + // A VarRef to something in another module before AstScope. + // Includes pin on a cell, as part of a ASSIGN statement to connect I/Os until AstScope +private: + string m_dotted; // Dotted part of scope the name()'ed reference is under or "" + string m_inlinedDots; // Dotted hierarchy flattened out +public: + AstVarXRef(FileLine* fl, const string& name, const string& dotted, const VAccess& access) + : ASTGEN_SUPER_VarXRef(fl, name, nullptr, access) + , m_dotted{dotted} {} + inline AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const VAccess& access); + ASTGEN_MEMBERS_VarXRef; + void dump(std::ostream& str) const override; + string dotted() const { return m_dotted; } + void dotted(const string& dotted) { m_dotted = dotted; } + string inlinedDots() const { return m_inlinedDots; } + void inlinedDots(const string& flag) { m_inlinedDots = flag; } + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + int instrCount() const override { return widthInstrs(); } + bool same(const AstNode* samep) const override { + const AstVarXRef* asamep = static_cast(samep); + return (selfPointer() == asamep->selfPointer() && varp() == asamep->varp() + && name() == asamep->name() && dotted() == asamep->dotted()); + } +}; + +#endif // Guard diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h new file mode 100644 index 000000000..c386496ed --- /dev/null +++ b/src/V3AstNodeOther.h @@ -0,0 +1,4133 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: AstNode sub-types representing other constructs +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2022 by Wilson Snyder. This program is free software; you +// can redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* +// +// This files contains all 'AstNode' sub-types that relate to other constructs +// not covered by the more speficic V3AstNode*.h files. +// +//************************************************************************* + +#ifndef VERILATOR_V3ASTNODES_H_ +#define VERILATOR_V3ASTNODES_H_ + +#ifndef VERILATOR_V3AST_H_ +#error "Use V3Ast.h as the include" +#include "V3Ast.h" // This helps code analysis tools pick up symbols in V3Ast.h +#define VL_NOT_FINAL // This #define fixes broken code folding in the CLion IDE +#endif + +// === Abstract base node types (AstNode*) ===================================== + +class AstNodeBlock VL_NOT_FINAL : public AstNode { + // A Begin/fork block + // @astgen op1 := stmtsp : List[AstNode] + // Parents: statement +private: + string m_name; // Name of block + bool m_unnamed; // Originally unnamed (name change does not affect this) +protected: + AstNodeBlock(VNType t, FileLine* fl, const string& name, AstNode* stmtsp) + : AstNode{t, fl} + , m_name{name} { + addStmtsp(stmtsp); + m_unnamed = (name == ""); + } + +public: + ASTGEN_MEMBERS_NodeBlock; + void dump(std::ostream& str) const override; + string name() const override { return m_name; } // * = Block name + void name(const string& name) override { m_name = name; } + bool unnamed() const { return m_unnamed; } + bool isFirstInMyListOfStatements(AstNode* nodep) const override { return nodep == stmtsp(); } +}; +class AstNodeFTask VL_NOT_FINAL : public AstNode { + // Output variable in functions, nullptr in tasks + // @astgen op1 := fvarp : Optional[AstNode] + // Class/package scope + // @astgen op2 := classOrPackagep : Optional[AstNode] + // Statements/Ports/Vars + // @astgen op3 := stmtsp : List[AstNode] + // Scope name + // @astgen op4 := scopeNamep : Optional[AstScopeName] +private: + string m_name; // Name of task + string m_cname; // Name of task if DPI import + uint64_t m_dpiOpenParent = 0; // DPI import open array, if !=0, how many callees + bool m_taskPublic : 1; // Public task + bool m_attrIsolateAssign : 1; // User isolate_assignments attribute + bool m_classMethod : 1; // Class method + bool m_externProto : 1; // Extern prototype + bool m_externDef : 1; // Extern definition + bool m_prototype : 1; // Just a prototype + bool m_dpiExport : 1; // DPI exported + bool m_dpiImport : 1; // DPI imported + bool m_dpiContext : 1; // DPI import context + bool m_dpiOpenChild : 1; // DPI import open array child wrapper + bool m_dpiTask : 1; // DPI import task (vs. void function) + bool m_dpiTraceInit : 1; // DPI trace_init + bool m_isConstructor : 1; // Class constructor + bool m_isHideLocal : 1; // Verilog local + bool m_isHideProtected : 1; // Verilog protected + bool m_pure : 1; // DPI import pure (vs. virtual pure) + bool m_pureVirtual : 1; // Pure virtual + bool m_recursive : 1; // Recusive or part of recursion + bool m_underGenerate : 1; // Under generate (for warning) + bool m_virtual : 1; // Virtual method in class + VLifetime m_lifetime; // Lifetime +protected: + AstNodeFTask(VNType t, FileLine* fl, const string& name, AstNode* stmtsp) + : AstNode{t, fl} + , m_name{name} + , m_taskPublic{false} + , m_attrIsolateAssign{false} + , m_classMethod{false} + , m_externProto{false} + , m_externDef{false} + , m_prototype{false} + , m_dpiExport{false} + , m_dpiImport{false} + , m_dpiContext{false} + , m_dpiOpenChild{false} + , m_dpiTask{false} + , m_dpiTraceInit{false} + , m_isConstructor{false} + , m_isHideLocal{false} + , m_isHideProtected{false} + , m_pure{false} + , m_pureVirtual{false} + , m_recursive{false} + , m_underGenerate{false} + , m_virtual{false} { + addStmtsp(stmtsp); + cname(name); // Might be overridden by dpi import/export + } + +public: + ASTGEN_MEMBERS_NodeFTask; + void dump(std::ostream& str = std::cout) const override; + string name() const override { return m_name; } // * = Var name + bool maybePointedTo() const override { return true; } + bool isGateOptimizable() const override { return !((m_dpiExport || m_dpiImport) && !m_pure); } + // {AstFunc only} op1 = Range output variable + void name(const string& name) override { m_name = name; } + string cname() const { return m_cname; } + void cname(const string& cname) { m_cname = cname; } + bool isFunction() const { return fvarp() != nullptr; } + // MORE ACCESSORS + void dpiOpenParentInc() { ++m_dpiOpenParent; } + void dpiOpenParentClear() { m_dpiOpenParent = 0; } + uint64_t dpiOpenParent() const { return m_dpiOpenParent; } + void taskPublic(bool flag) { m_taskPublic = flag; } + bool taskPublic() const { return m_taskPublic; } + void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; } + bool attrIsolateAssign() const { return m_attrIsolateAssign; } + void classMethod(bool flag) { m_classMethod = flag; } + bool classMethod() const { return m_classMethod; } + void isExternProto(bool flag) { m_externProto = flag; } + bool isExternProto() const { return m_externProto; } + void isExternDef(bool flag) { m_externDef = flag; } + bool isExternDef() const { return m_externDef; } + void prototype(bool flag) { m_prototype = flag; } + bool prototype() const { return m_prototype; } + void dpiExport(bool flag) { m_dpiExport = flag; } + bool dpiExport() const { return m_dpiExport; } + void dpiImport(bool flag) { m_dpiImport = flag; } + bool dpiImport() const { return m_dpiImport; } + void dpiContext(bool flag) { m_dpiContext = flag; } + bool dpiContext() const { return m_dpiContext; } + void dpiOpenChild(bool flag) { m_dpiOpenChild = flag; } + bool dpiOpenChild() const { return m_dpiOpenChild; } + void dpiTask(bool flag) { m_dpiTask = flag; } + bool dpiTask() const { return m_dpiTask; } + void dpiTraceInit(bool flag) { m_dpiTraceInit = flag; } + bool dpiTraceInit() const { return m_dpiTraceInit; } + void isConstructor(bool flag) { m_isConstructor = flag; } + bool isConstructor() const { return m_isConstructor; } + bool isHideLocal() const { return m_isHideLocal; } + void isHideLocal(bool flag) { m_isHideLocal = flag; } + bool isHideProtected() const { return m_isHideProtected; } + void isHideProtected(bool flag) { m_isHideProtected = flag; } + void pure(bool flag) { m_pure = flag; } + bool pure() const { return m_pure; } + void pureVirtual(bool flag) { m_pureVirtual = flag; } + bool pureVirtual() const { return m_pureVirtual; } + void recursive(bool flag) { m_recursive = flag; } + bool recursive() const { return m_recursive; } + void underGenerate(bool flag) { m_underGenerate = flag; } + bool underGenerate() const { return m_underGenerate; } + void isVirtual(bool flag) { m_virtual = flag; } + bool isVirtual() const { return m_virtual; } + void lifetime(const VLifetime& flag) { m_lifetime = flag; } + VLifetime lifetime() const { return m_lifetime; } + bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); } +}; +class AstNodeFile VL_NOT_FINAL : public AstNode { + // Emitted Otput file + // Parents: NETLIST + // @astgen op1 := tblockp : Optional[AstTextBlock] +private: + string m_name; ///< Filename +public: + AstNodeFile(VNType t, FileLine* fl, const string& name) + : AstNode{t, fl} + , m_name{name} {} + ASTGEN_MEMBERS_NodeFile; + void dump(std::ostream& str) const override; + string name() const override { return m_name; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstNodeModule VL_NOT_FINAL : public AstNode { + // A module, package, program or interface declaration; + // something that can live directly under the TOP, + // excluding $unit package stuff + // @astgen op1 := inlinesp : List[AstNode] + // @astgen op2 := stmtsp : List[AstNode] + // @astgen op3 := activesp : List[AstActive] +private: + string m_name; // Name of the module + const string m_origName; // Name of the module, ignoring name() changes, for dot lookup + string m_someInstanceName; // Hierarchical name of some arbitrary instance of this module. + // Used for user messages only. + bool m_modPublic : 1; // Module has public references + bool m_modTrace : 1; // Tracing this module + bool m_inLibrary : 1; // From a library, no error if not used, never top level + bool m_dead : 1; // LinkDot believes is dead; will remove in Dead visitors + bool m_hierBlock : 1; // Hiearchical Block marked by HIER_BLOCK pragma + bool m_internal : 1; // Internally created + bool m_recursive : 1; // Recursive module + bool m_recursiveClone : 1; // If recursive, what module it clones, otherwise nullptr + int m_level = 0; // 1=top module, 2=cell off top module, ... + VLifetime m_lifetime; // Lifetime + VTimescale m_timeunit; // Global time unit + VOptionBool m_unconnectedDrive; // State of `unconnected_drive +protected: + AstNodeModule(VNType t, FileLine* fl, const string& name) + : AstNode{t, fl} + , m_name{name} + , m_origName{name} + , m_modPublic{false} + , m_modTrace{false} + , m_inLibrary{false} + , m_dead{false} + , m_hierBlock{false} + , m_internal{false} + , m_recursive{false} + , m_recursiveClone{false} {} + +public: + ASTGEN_MEMBERS_NodeModule; + void dump(std::ostream& str) const override; + bool maybePointedTo() const override { return true; } + string name() const override { return m_name; } + virtual bool timescaleMatters() const = 0; + // ACCESSORS + void name(const string& name) override { m_name = name; } + string origName() const override { return m_origName; } + string someInstanceName() const { return m_someInstanceName; } + void someInstanceName(const string& name) { m_someInstanceName = name; } + bool inLibrary() const { return m_inLibrary; } + void inLibrary(bool flag) { m_inLibrary = flag; } + void level(int level) { m_level = level; } + int level() const { return m_level; } + bool isTop() const { return level() == 1; } + void modPublic(bool flag) { m_modPublic = flag; } + bool modPublic() const { return m_modPublic; } + void modTrace(bool flag) { m_modTrace = flag; } + bool modTrace() const { return m_modTrace; } + void dead(bool flag) { m_dead = flag; } + bool dead() const { return m_dead; } + void hierBlock(bool flag) { m_hierBlock = flag; } + bool hierBlock() const { return m_hierBlock; } + void internal(bool flag) { m_internal = flag; } + bool internal() const { return m_internal; } + void recursive(bool flag) { m_recursive = flag; } + bool recursive() const { return m_recursive; } + void recursiveClone(bool flag) { m_recursiveClone = flag; } + bool recursiveClone() const { return m_recursiveClone; } + void lifetime(const VLifetime& flag) { m_lifetime = flag; } + VLifetime lifetime() const { return m_lifetime; } + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } + void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; } + VOptionBool unconnectedDrive() const { return m_unconnectedDrive; } +}; +class AstNodePreSel VL_NOT_FINAL : public AstNode { + // Something that becomes an AstSel + // @astgen op1 := fromp : AstNode + // @astgen op2 := rhsp : AstNode + // @astgen op3 := thsp : Optional[AstNode] + // @astgen op4 := attrp : Optional[AstAttrOf] +protected: + AstNodePreSel(VNType t, FileLine* fl, AstNode* fromp, AstNode* rhsp, AstNode* thsp) + : AstNode{t, fl} { + this->fromp(fromp); + this->rhsp(rhsp); + this->thsp(thsp); + } + +public: + ASTGEN_MEMBERS_NodePreSel; + // METHODS + bool same(const AstNode*) const override { return true; } +}; +class AstNodeProcedure VL_NOT_FINAL : public AstNode { + // IEEE procedure: initial, final, always + // @astgen op2 := stmtsp : List[AstNode] // Note: op1 is used in some sub-types only +protected: + AstNodeProcedure(VNType t, FileLine* fl, AstNode* stmtsp) + : AstNode{t, fl} { + addStmtsp(stmtsp); + } + +public: + ASTGEN_MEMBERS_NodeProcedure; + // METHODS + void dump(std::ostream& str) const override; + bool isJustOneBodyStmt() const { return stmtsp() && !stmtsp()->nextp(); } +}; +class AstNodeRange VL_NOT_FINAL : public AstNode { + // A range, sized or unsized +protected: + AstNodeRange(VNType t, FileLine* fl) + : AstNode{t, fl} {} + +public: + ASTGEN_MEMBERS_NodeRange; + void dump(std::ostream& str) const override; +}; +class AstNodeStmt VL_NOT_FINAL : public AstNode { + // Statement -- anything that's directly under a function + bool m_statement; // Really a statement (e.g. not a function with return) +protected: + AstNodeStmt(VNType t, FileLine* fl, bool statement = true) + : AstNode{t, fl} + , m_statement{statement} {} + +public: + ASTGEN_MEMBERS_NodeStmt; + // METHODS + bool isStatement() const { return m_statement; } // Really a statement + void statement(bool flag) { m_statement = flag; } + void addNextStmt(AstNode* newp, + AstNode* belowp) override; // Stop statement searchback here + void addBeforeStmt(AstNode* newp, + AstNode* belowp) override; // Stop statement searchback here + void dump(std::ostream& str = std::cout) const override; +}; +class AstNodeAssign VL_NOT_FINAL : public AstNodeStmt { + // Iteration is in order, and we want rhsp to be visited first (which is the execution order) + // @astgen op1 := rhsp : AstNode + // @astgen op2 := lhsp : AstNode + // @astgen op3 := timingControlp : Optional[AstNode] +protected: + AstNodeAssign(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp, + AstNode* timingControlp = nullptr) + : AstNodeStmt{t, fl} { + this->rhsp(rhsp); + this->lhsp(lhsp); + this->timingControlp(timingControlp); + dtypeFrom(lhsp); + } + +public: + ASTGEN_MEMBERS_NodeAssign; + // Clone single node, just get same type back. + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) = 0; + bool hasDType() const override { return true; } + virtual bool cleanRhs() const { return true; } + int instrCount() const override { return widthInstrs(); } + bool same(const AstNode*) const override { return true; } + string verilogKwd() const override { return "="; } + virtual bool brokeLhsMustBeLvalue() const = 0; +}; +class AstNodeCCall VL_NOT_FINAL : public AstNodeStmt { + // A call of a C++ function, perhaps a AstCFunc or perhaps globally named + // @astgen op2 := argsp : List[AstNode] // Note: op1 used by some sub-types only + // + // Functions are not statements, while tasks are. AstNodeStmt needs isStatement() to deal. + AstCFunc* m_funcp; + string m_argTypes; + +protected: + AstNodeCCall(VNType t, FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) + : AstNodeStmt{t, fl, true} + , m_funcp{funcp} { + addArgsp(argsp); + } + +public: + ASTGEN_MEMBERS_NodeCCall; + void dump(std::ostream& str = std::cout) const override; + void cloneRelink() override; + const char* broken() const override; + int instrCount() const override { return INSTR_COUNT_CALL; } + bool same(const AstNode* samep) const override { + const AstNodeCCall* const asamep = static_cast(samep); + return (funcp() == asamep->funcp() && argTypes() == asamep->argTypes()); + } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override; + bool isOutputter() const override { return !isPure(); } + AstCFunc* funcp() const { return m_funcp; } + void funcp(AstCFunc* funcp) { m_funcp = funcp; } + void argTypes(const string& str) { m_argTypes = str; } + string argTypes() const { return m_argTypes; } +}; +class AstNodeCase VL_NOT_FINAL : public AstNodeStmt { + // @astgen op1 := exprp : AstNode // Condition (scurtinee) expression + // @astgen op2 := itemsp : List[AstCaseItem] + // @astgen op3 := notParallelp : List[AstNode] // assertion code for non-full case's +protected: + AstNodeCase(VNType t, FileLine* fl, AstNode* exprp, AstCaseItem* itemsp) + : AstNodeStmt{t, fl} { + this->exprp(exprp); + this->addItemsp(itemsp); + } + +public: + ASTGEN_MEMBERS_NodeCase; + int instrCount() const override { return INSTR_COUNT_BRANCH; } +}; +class AstNodeCoverOrAssert VL_NOT_FINAL : public AstNodeStmt { + // Cover or Assert + // Parents: {statement list} + // @astgen op1 := propp : AstNode + // @astgen op2 := sentreep : Optional[AstSenTree] + // op3 used by some sub-types only + // @astgen op4 := passsp: List[AstNode] // Statments when propp is passing/truthly + const bool m_immediate; // Immediate assertion/cover + string m_name; // Name to report +public: + AstNodeCoverOrAssert(VNType t, FileLine* fl, AstNode* propp, AstNode* passsp, bool immediate, + const string& name = "") + : AstNodeStmt{t, fl} + , m_immediate{immediate} + , m_name{name} { + this->propp(propp); + this->addPasssp(passsp); + } + ASTGEN_MEMBERS_NodeCoverOrAssert; + string name() const override { return m_name; } // * = Var name + bool same(const AstNode* samep) const override { return samep->name() == name(); } + void name(const string& name) override { m_name = name; } + void dump(std::ostream& str = std::cout) const override; + bool immediate() const { return m_immediate; } +}; +class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeStmt { + // A reference to a task (or function) + // @astgen op1 := namep : Optional[AstNode] + // op2 used by some sub-types only + // @astgen op3 := pinsp : List[AstNode] + // @astgen op4 := scopeNamep : Optional[AstScopeName] + // + // Functions are not statements, while tasks are. AstNodeStmt needs isStatement() to deal. +private: + AstNodeFTask* m_taskp = nullptr; // [AfterLink] Pointer to task referenced + AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy + string m_name; // Name of variable + string m_dotted; // Dotted part of scope the name()ed task/func is under or "" + string m_inlinedDots; // Dotted hierarchy flattened out + bool m_pli = false; // Pli system call ($name) +protected: + AstNodeFTaskRef(VNType t, FileLine* fl, bool statement, AstNode* namep, AstNode* pinsp) + : AstNodeStmt{t, fl, statement} { + this->namep(namep); + this->addPinsp(pinsp); + } + AstNodeFTaskRef(VNType t, FileLine* fl, bool statement, const string& name, AstNode* pinsp) + : AstNodeStmt{t, fl, statement} + , m_name{name} { + this->addPinsp(pinsp); + } + +public: + ASTGEN_MEMBERS_NodeFTaskRef; + const char* broken() const override; + void cloneRelink() override; + void dump(std::ostream& str = std::cout) const override; + string name() const override { return m_name; } // * = Var name + bool isGateOptimizable() const override { return m_taskp && m_taskp->isGateOptimizable(); } + string dotted() const { return m_dotted; } // * = Scope name or "" + string inlinedDots() const { return m_inlinedDots; } + void inlinedDots(const string& flag) { m_inlinedDots = flag; } + AstNodeFTask* taskp() const { return m_taskp; } // [After Link] Pointer to variable + void taskp(AstNodeFTask* taskp) { m_taskp = taskp; } + void name(const string& name) override { m_name = name; } + void dotted(const string& name) { m_dotted = name; } + AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } + void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } + bool pli() const { return m_pli; } + void pli(bool flag) { m_pli = flag; } +}; +class AstNodeFor VL_NOT_FINAL : public AstNodeStmt { + // @astgen op1 := initsp : List[AstNode] + // @astgen op2 := condp : AstNode + // @astgen op3 := incsp : List[AstNode] + // @astgen op4 := stmtsp : List[AstNode] +protected: + AstNodeFor(VNType t, FileLine* fl, AstNode* initsp, AstNode* condp, AstNode* incsp, + AstNode* stmtsp) + : AstNodeStmt{t, fl} { + this->addInitsp(initsp); + this->condp(condp); + this->addIncsp(incsp); + this->addStmtsp(stmtsp); + } + +public: + ASTGEN_MEMBERS_NodeFor; + bool isGateOptimizable() const override { return false; } + int instrCount() const override { return INSTR_COUNT_BRANCH; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstNodeIf VL_NOT_FINAL : public AstNodeStmt { + // @astgen op1 := condp : AstNode + // @astgen op2 := thensp : List[AstNode] + // @astgen op3 := elsesp : List[AstNode] +private: + VBranchPred m_branchPred; // Branch prediction as taken/untaken? + bool m_isBoundsCheck; // True if this if node was inserted for array bounds checking +protected: + AstNodeIf(VNType t, FileLine* fl, AstNode* condp, AstNode* thensp, AstNode* elsesp) + : AstNodeStmt{t, fl} { + this->condp(condp); + this->addThensp(thensp); + this->addElsesp(elsesp); + isBoundsCheck(false); + } + +public: + ASTGEN_MEMBERS_NodeIf; + bool isGateOptimizable() const override { return false; } + bool isGateDedupable() const override { return true; } + int instrCount() const override { return INSTR_COUNT_BRANCH; } + bool same(const AstNode* /*samep*/) const override { return true; } + void branchPred(VBranchPred flag) { m_branchPred = flag; } + VBranchPred branchPred() const { return m_branchPred; } + void isBoundsCheck(bool flag) { m_isBoundsCheck = flag; } + bool isBoundsCheck() const { return m_isBoundsCheck; } + bool isFirstInMyListOfStatements(AstNode* n) const override { + return n == thensp() || n == elsesp(); + } +}; +class AstNodeReadWriteMem VL_NOT_FINAL : public AstNodeStmt { + // @astgen op1 := filenamep : AstNode + // @astgen op2 := memp : AstNode + // @astgen op3 := lsbp : Optional[AstNode] + // @astgen op4 := msbp : Optional[AstNode] + + const bool m_isHex; // readmemh, not readmemb +public: + AstNodeReadWriteMem(VNType t, FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, + AstNode* lsbp, AstNode* msbp) + : AstNodeStmt(t, fl) + , m_isHex(hex) { + this->filenamep(filenamep); + this->memp(memp); + this->lsbp(lsbp); + this->msbp(msbp); + } + ASTGEN_MEMBERS_NodeReadWriteMem; + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } + bool isOutputter() const override { return true; } + bool isUnlikely() const override { return true; } + bool same(const AstNode* samep) const override { + return isHex() == static_cast(samep)->isHex(); + } + bool isHex() const { return m_isHex; } + virtual const char* cFuncPrefixp() const = 0; +}; +class AstNodeText VL_NOT_FINAL : public AstNode { +private: + string m_text; + +protected: + // Node that puts text into the output stream + AstNodeText(VNType t, FileLine* fl, const string& text) + : AstNode{t, fl} + , m_text{text} {} + +public: + ASTGEN_MEMBERS_NodeText; + void dump(std::ostream& str = std::cout) const override; + bool same(const AstNode* samep) const override { + const AstNodeText* asamep = static_cast(samep); + return text() == asamep->text(); + } + const string& text() const { return m_text; } +}; +class AstNodeSimpleText VL_NOT_FINAL : public AstNodeText { +private: + bool m_tracking; // When emit, it's ok to parse the string to do indentation +public: + AstNodeSimpleText(VNType t, FileLine* fl, const string& textp, bool tracking = false) + : AstNodeText(t, fl, textp) + , m_tracking(tracking) {} + ASTGEN_MEMBERS_NodeSimpleText; + void tracking(bool flag) { m_tracking = flag; } + bool tracking() const { return m_tracking; } +}; + +// === Concrete node types ===================================================== + +// === AstNode === +class AstActive final : public AstNode { + // Block of code with sensitivity activation + // Parents: MODULE | CFUNC + // @astgen op1 := sensesStorep : Optional[AstSenTree] // Moved into m_sensesp in V3Active + // @astgen op2 := stmtsp : List[AstNode] // Logic +private: + string m_name; + AstSenTree* m_sensesp; + +public: + AstActive(FileLine* fl, const string& name, AstSenTree* sensesp) + : ASTGEN_SUPER_Active(fl) + , m_name{name} + , m_sensesp{sensesp} { + UASSERT(sensesp, "Sensesp required arg"); + } + ASTGEN_MEMBERS_Active; + void dump(std::ostream& str = std::cout) const override; + string name() const override { return m_name; } + const char* broken() const override; + void cloneRelink() override; + // Statements are broken into pieces, as some must come before others. + void sensesp(AstSenTree* nodep) { m_sensesp = nodep; } + AstSenTree* sensesp() const { return m_sensesp; } + // METHODS + inline bool hasInitial() const; + inline bool hasSettle() const; + inline bool hasClocked() const; +}; +class AstArg final : public AstNode { + // An argument to a function/task + // @astgen op1 := exprp : Optional[AstNode] // nullptr if omitted + string m_name; // Pin name, or "" for number based interconnect +public: + AstArg(FileLine* fl, const string& name, AstNode* exprp) + : ASTGEN_SUPER_Arg(fl) + , m_name{name} { + this->exprp(exprp); + } + ASTGEN_MEMBERS_Arg; + string name() const override { return m_name; } // * = Pin name, ""=go by number + void name(const string& name) override { m_name = name; } + bool emptyConnectNoNext() const { return !exprp() && name() == "" && !nextp(); } +}; +class AstAttrOf final : public AstNode { + // Return a value of a attribute, for example a LSB or array LSB of a signal + // @astgen op1 := fromp : Optional[AstNode] + // @astgen op2 := dimp : Optional[AstNode] + VAttrType m_attrType; // What sort of extraction +public: + AstAttrOf(FileLine* fl, VAttrType attrtype, AstNode* fromp = nullptr, AstNode* dimp = nullptr) + : ASTGEN_SUPER_AttrOf(fl) { + this->fromp(fromp); + this->dimp(dimp); + m_attrType = attrtype; + } + ASTGEN_MEMBERS_AttrOf; + VAttrType attrType() const { return m_attrType; } + void dump(std::ostream& str = std::cout) const override; +}; +class AstBind final : public AstNode { + // Parents: MODULE + // Children: CELL + // @astgen op1 := cellsp : List[AstNode] +private: + string m_name; // Binding to name +public: + AstBind(FileLine* fl, const string& name, AstNode* cellsp) + : ASTGEN_SUPER_Bind(fl) + , m_name{name} { + UASSERT_OBJ(VN_IS(cellsp, Cell), cellsp, "Only instances allowed to be bound"); + this->addCellsp(cellsp); + } + ASTGEN_MEMBERS_Bind; + // ACCESSORS + string name() const override { return m_name; } // * = Bind Target name + void name(const string& name) override { m_name = name; } +}; +class AstCFunc final : public AstNode { + // C++ function + // Parents: MODULE/SCOPE + // If adding node accessors, see below emptyBody + // @astgen op1 := argsp : List[AstNode] + // @astgen op2 := initsp : List[AstNode] + // @astgen op3 := stmtsp : List[AstNode] + // @astgen op4 := finalsp : List[AstNode] +private: + AstScope* m_scopep; + string m_name; + string m_cname; // C name, for dpiExports + string m_rtnType; // void, bool, or other return type + string m_argTypes; // Argument types + string m_ctorInits; // Constructor sub-class inits + string m_ifdef; // #ifdef symbol around this function + VBoolOrUnknown m_isConst; // Function is declared const (*this not changed) + bool m_isStatic : 1; // Function is static (no need for a 'this' pointer) + bool m_isTrace : 1; // Function is related to tracing + bool m_dontCombine : 1; // V3Combine shouldn't compare this func tree, it's special + bool m_declPrivate : 1; // Declare it private + bool m_isFinal : 1; // This is a function corresponding to a SystemVerilog 'final' block + bool m_slow : 1; // Slow routine, called once or just at init time + bool m_funcPublic : 1; // From user public task/function + bool m_isConstructor : 1; // Is C class constructor + bool m_isDestructor : 1; // Is C class destructor + bool m_isMethod : 1; // Is inside a class definition + bool m_isLoose : 1; // Semantically this is a method, but is implemented as a function + // with an explicitly passed 'self' pointer as the first argument + bool m_isInline : 1; // Inline function + bool m_isVirtual : 1; // Virtual function + bool m_entryPoint : 1; // User may call into this top level function + bool m_pure : 1; // Pure function + bool m_dpiContext : 1; // Declared as 'context' DPI import/export function + bool m_dpiExportDispatcher : 1; // This is the DPI export entry point (i.e.: called by user) + bool m_dpiExportImpl : 1; // DPI export implementation (called from DPI dispatcher via lookup) + bool m_dpiImportPrototype : 1; // This is the DPI import prototype (i.e.: provided by user) + bool m_dpiImportWrapper : 1; // Wrapper for invoking DPI import prototype from generated code + bool m_dpiTraceInit : 1; // DPI trace_init +public: + AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType = "") + : ASTGEN_SUPER_CFunc(fl) { + m_isConst = VBoolOrUnknown::BU_UNKNOWN; // Unknown until analyzed + m_scopep = scopep; + m_name = name; + m_rtnType = rtnType; + m_isStatic = false; + m_isTrace = false; + m_dontCombine = false; + m_declPrivate = false; + m_isFinal = false; + m_slow = false; + m_funcPublic = false; + m_isConstructor = false; + m_isDestructor = false; + m_isMethod = true; + m_isLoose = false; + m_isInline = false; + m_isVirtual = false; + m_entryPoint = false; + m_pure = false; + m_dpiContext = false; + m_dpiExportDispatcher = false; + m_dpiExportImpl = false; + m_dpiImportPrototype = false; + m_dpiImportWrapper = false; + m_dpiTraceInit = false; + } + ASTGEN_MEMBERS_CFunc; + string name() const override { return m_name; } + const char* broken() const override; + void cloneRelink() override; + bool maybePointedTo() const override { return true; } + void dump(std::ostream& str = std::cout) const override; + bool same(const AstNode* samep) const override { + const AstCFunc* const asamep = static_cast(samep); + return ((isTrace() == asamep->isTrace()) && (rtnTypeVoid() == asamep->rtnTypeVoid()) + && (argTypes() == asamep->argTypes()) && (ctorInits() == asamep->ctorInits()) + && isLoose() == asamep->isLoose() + && (!(dpiImportPrototype() || dpiExportImpl()) || name() == asamep->name())); + } + // + void name(const string& name) override { m_name = name; } + int instrCount() const override { + return dpiImportPrototype() ? v3Global.opt.instrCountDpi() : 0; + } + VBoolOrUnknown isConst() const { return m_isConst; } + void isConst(bool flag) { m_isConst.setTrueOrFalse(flag); } + void isConst(VBoolOrUnknown flag) { m_isConst = flag; } + bool isStatic() const { return m_isStatic; } + void isStatic(bool flag) { m_isStatic = flag; } + bool isTrace() const { return m_isTrace; } + void isTrace(bool flag) { m_isTrace = flag; } + void cname(const string& name) { m_cname = name; } + string cname() const { return m_cname; } + AstScope* scopep() const { return m_scopep; } + void scopep(AstScope* nodep) { m_scopep = nodep; } + string rtnTypeVoid() const { return ((m_rtnType == "") ? "void" : m_rtnType); } + bool dontCombine() const { return m_dontCombine || isTrace() || entryPoint(); } + void dontCombine(bool flag) { m_dontCombine = flag; } + bool dontInline() const { return dontCombine() || slow() || funcPublic(); } + bool declPrivate() const { return m_declPrivate; } + void declPrivate(bool flag) { m_declPrivate = flag; } + bool isFinal() const { return m_isFinal; } + void isFinal(bool flag) { m_isFinal = flag; } + bool slow() const { return m_slow; } + void slow(bool flag) { m_slow = flag; } + bool funcPublic() const { return m_funcPublic; } + void funcPublic(bool flag) { m_funcPublic = flag; } + void argTypes(const string& str) { m_argTypes = str; } + string argTypes() const { return m_argTypes; } + void ctorInits(const string& str) { m_ctorInits = str; } + string ctorInits() const { return m_ctorInits; } + void ifdef(const string& str) { m_ifdef = str; } + string ifdef() const { return m_ifdef; } + bool isConstructor() const { return m_isConstructor; } + void isConstructor(bool flag) { m_isConstructor = flag; } + bool isDestructor() const { return m_isDestructor; } + void isDestructor(bool flag) { m_isDestructor = flag; } + bool isMethod() const { return m_isMethod; } + void isMethod(bool flag) { m_isMethod = flag; } + bool isLoose() const { return m_isLoose; } + void isLoose(bool flag) { m_isLoose = flag; } + bool isProperMethod() const { return isMethod() && !isLoose(); } + bool isInline() const { return m_isInline; } + void isInline(bool flag) { m_isInline = flag; } + bool isVirtual() const { return m_isVirtual; } + void isVirtual(bool flag) { m_isVirtual = flag; } + bool entryPoint() const { return m_entryPoint; } + void entryPoint(bool flag) { m_entryPoint = flag; } + bool pure() const { return m_pure; } + void pure(bool flag) { m_pure = flag; } + bool dpiContext() const { return m_dpiContext; } + void dpiContext(bool flag) { m_dpiContext = flag; } + bool dpiExportDispatcher() const { return m_dpiExportDispatcher; } + void dpiExportDispatcher(bool flag) { m_dpiExportDispatcher = flag; } + bool dpiExportImpl() const { return m_dpiExportImpl; } + void dpiExportImpl(bool flag) { m_dpiExportImpl = flag; } + bool dpiImportPrototype() const { return m_dpiImportPrototype; } + void dpiImportPrototype(bool flag) { m_dpiImportPrototype = flag; } + bool dpiImportWrapper() const { return m_dpiImportWrapper; } + void dpiImportWrapper(bool flag) { m_dpiImportWrapper = flag; } + void dpiTraceInit(bool flag) { m_dpiTraceInit = flag; } + bool dpiTraceInit() const { return m_dpiTraceInit; } + // Special methods + bool emptyBody() const { + return argsp() == nullptr && initsp() == nullptr && stmtsp() == nullptr + && finalsp() == nullptr; + } +}; +class AstCUse final : public AstNode { + // C++ use of a class or #include; indicates need of forward declaration + // Parents: NODEMODULE +private: + const VUseType m_useType; // What sort of use this is + const string m_name; + +public: + AstCUse(FileLine* fl, VUseType useType, const string& name) + : ASTGEN_SUPER_CUse(fl) + , m_useType{useType} + , m_name{name} {} + ASTGEN_MEMBERS_CUse; + void dump(std::ostream& str = std::cout) const override; + string name() const override { return m_name; } + VUseType useType() const { return m_useType; } +}; +class AstCaseItem final : public AstNode { + // Single item of a case statement + // @astgen op1 := condsp : List[AstNode] + // @astgen op2 := stmtsp : List[AstNode] +public: + AstCaseItem(FileLine* fl, AstNode* condsp, AstNode* stmtsp) + : ASTGEN_SUPER_CaseItem(fl) { + this->addCondsp(condsp); + this->addStmtsp(stmtsp); + } + ASTGEN_MEMBERS_CaseItem; + int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } + bool isDefault() const { return condsp() == nullptr; } + bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); } +}; +class AstCast final : public AstNode { + // Cast to appropriate data type + // @astgen op1 := fromp : AstNode + // @astgen op2 := childDTypep : Optional[AstNodeDType] +public: + AstCast(FileLine* fl, AstNode* fromp, VFlagChildDType, AstNodeDType* dtp) + : ASTGEN_SUPER_Cast(fl) { + this->fromp(fromp); + this->childDTypep(dtp); + dtypeFrom(dtp); + } + AstCast(FileLine* fl, AstNode* fromp, AstNodeDType* dtp) + : ASTGEN_SUPER_Cast(fl) { + this->fromp(fromp); + dtypeFrom(dtp); + } + ASTGEN_MEMBERS_Cast; + bool hasDType() const override { return true; } + virtual string emitVerilog() { return "((%d)'(%l))"; } + virtual bool cleanOut() const { V3ERROR_NA_RETURN(true); } + virtual bool cleanLhs() const { return true; } + virtual bool sizeMattersLhs() const { return false; } + AstNodeDType* getChildDTypep() const override { return childDTypep(); } + virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } +}; +class AstCastParse final : public AstNode { + // Cast to appropriate type, where we haven't determined yet what the data type is + // @astgen op1 := lhsp : AstNode + // @astgen op2 := dtp : AstNode +public: + AstCastParse(FileLine* fl, AstNode* lhsp, AstNode* dtp) + : ASTGEN_SUPER_CastParse(fl) { + this->lhsp(lhsp); + this->dtp(dtp); + } + ASTGEN_MEMBERS_CastParse; + virtual string emitVerilog() { return "((%d)'(%l))"; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const { V3ERROR_NA_RETURN(true); } + virtual bool cleanLhs() const { return true; } + virtual bool sizeMattersLhs() const { return false; } +}; +class AstCastSize final : public AstNode { + // Cast to specific size; signed/twostate inherited from lower element per IEEE + // @astgen op1 := lhsp : AstNode + // @astgen op2 := rhsp : AstNode +public: + AstCastSize(FileLine* fl, AstNode* lhsp, AstConst* rhsp) + : ASTGEN_SUPER_CastSize(fl) { + this->lhsp(lhsp); + this->rhsp(rhsp); + } + ASTGEN_MEMBERS_CastSize; + // No hasDType because widthing removes this node before the hasDType check + virtual string emitVerilog() { return "((%r)'(%l))"; } + virtual bool cleanOut() const { V3ERROR_NA_RETURN(true); } + virtual bool cleanLhs() const { return true; } + virtual bool sizeMattersLhs() const { return false; } +}; +class AstCell final : public AstNode { + // A instantiation cell or interface call (don't know which until link) + // @astgen op1 := pinsp : List[AstPin] // List of port assignments + // @astgen op2 := paramsp : List[AstPin] // List of parameter assignments + // @astgen op3 := rangep : Optional[AstRange] // Range for arrayed instances + // @astgen op4 := intfRefsp : List[AstIntfRef] // List of interface references + FileLine* m_modNameFileline; // Where module the cell instances token was + string m_name; // Cell name + string m_origName; // Original name before dot addition + string m_modName; // Module the cell instances + AstNodeModule* m_modp = nullptr; // [AfterLink] Pointer to module instanced + bool m_hasIfaceVar : 1; // True if a Var has been created for this cell + bool m_recursive : 1; // Self-recursive module + bool m_trace : 1; // Trace this cell +public: + AstCell(FileLine* fl, FileLine* mfl, const string& instName, const string& modName, + AstPin* pinsp, AstPin* paramsp, AstRange* rangep) + : ASTGEN_SUPER_Cell(fl) + , m_modNameFileline{mfl} + , m_name{instName} + , m_origName{instName} + , m_modName{modName} + , m_hasIfaceVar{false} + , m_recursive{false} + , m_trace{true} { + this->addPinsp(pinsp); + this->addParamsp(paramsp); + this->rangep(rangep); + } + ASTGEN_MEMBERS_Cell; + // No cloneRelink, we presume cloneee's want the same module linkages + void dump(std::ostream& str) const override; + const char* broken() const override; + bool maybePointedTo() const override { return true; } + // ACCESSORS + string name() const override { return m_name; } // * = Cell name + void name(const string& name) override { m_name = name; } + string origName() const override { return m_origName; } // * = Original name + void origName(const string& name) { m_origName = name; } + string modName() const { return m_modName; } // * = Instance name + void modName(const string& name) { m_modName = name; } + FileLine* modNameFileline() const { return m_modNameFileline; } + AstNodeModule* modp() const { return m_modp; } // [AfterLink] = Pointer to module instantiated + void modp(AstNodeModule* nodep) { m_modp = nodep; } + bool hasIfaceVar() const { return m_hasIfaceVar; } + void hasIfaceVar(bool flag) { m_hasIfaceVar = flag; } + void trace(bool flag) { m_trace = flag; } + bool isTrace() const { return m_trace; } + void recursive(bool flag) { m_recursive = flag; } + bool recursive() const { return m_recursive; } +}; +class AstCellArrayRef final : public AstNode { + // As-of-yet unlinkable reference into an array of cells + // @astgen op1 := selp : List[AstNode] // Select expression + string m_name; // Array name +public: + AstCellArrayRef(FileLine* fl, const string& name, AstNode* selp) + : ASTGEN_SUPER_CellArrayRef(fl) + , m_name{name} { + this->addSelp(selp); + } + ASTGEN_MEMBERS_CellArrayRef; + // ACCESSORS + string name() const override { return m_name; } // * = Array name +}; +class AstCellInline final : public AstNode { + // A instantiation cell that was removed by inlining + // For communication between V3Inline and V3LinkDot, + // except for VPI runs where it exists until the end. + // It is augmented with the scope in V3Scope for VPI. + // Children: When 2 levels inlined, other CellInline under this +private: + string m_name; // Cell name, possibly {a}__DOT__{b}... + const string + m_origModName; // Original name of the module, ignoring name() changes, for dot lookup + AstScope* m_scopep = nullptr; // The scope that the cell is inlined into + VTimescale m_timeunit; // Parent module time unit +public: + AstCellInline(FileLine* fl, const string& name, const string& origModName, + const VTimescale& timeunit) + : ASTGEN_SUPER_CellInline(fl) + , m_name{name} + , m_origModName{origModName} + , m_timeunit{timeunit} {} + ASTGEN_MEMBERS_CellInline; + void dump(std::ostream& str) const override; + const char* broken() const override; + // ACCESSORS + string name() const override { return m_name; } // * = Cell name + string origModName() const { return m_origModName; } // * = modp()->origName() before inlining + void name(const string& name) override { m_name = name; } + void scopep(AstScope* scp) { m_scopep = scp; } + AstScope* scopep() const { return m_scopep; } + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } +}; +class AstCellRef final : public AstNode { + // As-of-yet unlinkable reference into a cell + // @astgen op1 := cellp : AstNode + // @astgen op2 := exprp : AstNode +private: + string m_name; // Cell name +public: + AstCellRef(FileLine* fl, const string& name, AstNode* cellp, AstNode* exprp) + : ASTGEN_SUPER_CellRef(fl) + , m_name{name} { + this->cellp(cellp); + this->exprp(exprp); + } + ASTGEN_MEMBERS_CellRef; + // ACCESSORS + string name() const override { return m_name; } // * = Array name +}; +class AstClassExtends final : public AstNode { + // Children: List of AstParseRef for packages/classes + // during early parse, then moves to dtype + // @astgen op1 := childDTypep : Optional[AstNodeDType] + // @astgen op2 := classOrPkgsp : Optional[AstNode] +public: + AstClassExtends(FileLine* fl, AstNode* classOrPkgsp) + : ASTGEN_SUPER_ClassExtends(fl) { + this->classOrPkgsp(classOrPkgsp); // Only for parser + } + ASTGEN_MEMBERS_ClassExtends; + bool hasDType() const override { return true; } + string verilogKwd() const override { return "extends"; } + AstClass* classp() const; // Class being extended (after link) +}; +class AstClassOrPackageRef final : public AstNode { + // @astgen op1 := paramsp : List[AstPin] +private: + string m_name; + // Node not NodeModule to appease some early parser usage + AstNode* m_classOrPackageNodep; // Package hierarchy +public: + AstClassOrPackageRef(FileLine* fl, const string& name, AstNode* classOrPackageNodep, + AstPin* paramsp) + : ASTGEN_SUPER_ClassOrPackageRef(fl) + , m_name{name} + , m_classOrPackageNodep{classOrPackageNodep} { + this->addParamsp(paramsp); + } + ASTGEN_MEMBERS_ClassOrPackageRef; + // METHODS + const char* broken() const override { + BROKEN_RTN(m_classOrPackageNodep && !m_classOrPackageNodep->brokeExists()); + return nullptr; + } + void cloneRelink() override { + if (m_classOrPackageNodep && m_classOrPackageNodep->clonep()) { + m_classOrPackageNodep = m_classOrPackageNodep->clonep(); + } + } + bool same(const AstNode* samep) const override { + return (m_classOrPackageNodep + == static_cast(samep)->m_classOrPackageNodep); + } + void dump(std::ostream& str = std::cout) const override; + string name() const override { return m_name; } // * = Var name + AstNode* classOrPackageNodep() const { return m_classOrPackageNodep; } + void classOrPackageNodep(AstNode* nodep) { m_classOrPackageNodep = nodep; } + AstNodeModule* classOrPackagep() const; + AstPackage* packagep() const { return VN_CAST(classOrPackageNodep(), Package); } + void classOrPackagep(AstNodeModule* nodep) { m_classOrPackageNodep = (AstNode*)nodep; } +}; +class AstClocking final : public AstNode { + // Set default clock region + // Parents: MODULE + // @astgen op1 := sensesp : List[AstSenItem] + // @astgen op2 := bodysp : List[AstNode] +public: + AstClocking(FileLine* fl, AstSenItem* sensesp, AstNode* bodysp) + : ASTGEN_SUPER_Clocking(fl) { + this->addSensesp(sensesp); + this->addBodysp(bodysp); + } + ASTGEN_MEMBERS_Clocking; +}; +class AstConstPool final : public AstNode { + // Container for const static data + // @astgen op1 := modulep : AstModule // m_modp below TODO: fix this mess + std::unordered_multimap m_tables; // Constant tables (unpacked arrays) + std::unordered_multimap m_consts; // Constant tables (scalars) + AstModule* const m_modp; // The Module holding the Scope below ... + AstScope* const m_scopep; // Scope holding the constant variables + + AstVarScope* createNewEntry(const string& name, AstNode* initp); + +public: + explicit AstConstPool(FileLine* fl); + ASTGEN_MEMBERS_ConstPool; + bool maybePointedTo() const override { return true; } + const char* broken() const override; + void cloneRelink() override { V3ERROR_NA; } + AstModule* modp() const { return m_modp; } + + // Find a table (unpacked array) within the constant pool which is initialized with the + // given value, or create one if one does not already exists. The returned VarScope *might* + // have a different dtype than the given initp->dtypep(), including a different element type, + // but it will always have the same size and element width. In contexts where this matters, + // the caller must handle the dtype difference as appropriate. + AstVarScope* findTable(AstInitArray* initp); + // Find a constant within the constant pool which is initialized with the given value, or + // create one if one does not already exists. If 'mergeDType' is true, then the returned + // VarScope *might* have a different type than the given initp->dtypep(). In contexts where + // this matters, the caller must handle the dtype difference as appropriate. If 'mergeDType' is + // false, the returned VarScope will have _->dtypep()->sameTree(initp->dtypep()) return true. + AstVarScope* findConst(AstConst* initp, bool mergeDType); +}; +class AstDefParam final : public AstNode { + // A defparam assignment + // Parents: MODULE + // @astgen op1 := rhsp : AstNode + string m_name; // Name of variable getting set + string m_path; // Dotted cellname to set parameter of +public: + AstDefParam(FileLine* fl, const string& path, const string& name, AstNode* rhsp) + : ASTGEN_SUPER_DefParam(fl) + , m_name{name} + , m_path{path} { + this->rhsp(rhsp); + } + string name() const override { return m_name; } // * = Scope name + ASTGEN_MEMBERS_DefParam; + bool same(const AstNode*) const override { return true; } + string path() const { return m_path; } +}; +class AstDot final : public AstNode { + // A dot separating paths in an AstVarXRef, AstFuncRef or AstTaskRef + // These are eliminated in the link stage + // @astgen op1 := lhsp : AstNode + // @astgen op2 := rhsp : AstNode + const bool m_colon; // Is a "::" instead of a "." (lhs must be package/class) +public: + AstDot(FileLine* fl, bool colon, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_Dot(fl) + , m_colon{colon} { + this->lhsp(lhsp); + this->rhsp(rhsp); + } + ASTGEN_MEMBERS_Dot; + // For parser, make only if non-null package + static AstNode* newIfPkg(FileLine* fl, AstNode* packageOrClassp, AstNode* rhsp) { + if (!packageOrClassp) return rhsp; + return new AstDot(fl, true, packageOrClassp, rhsp); + } + void dump(std::ostream& str) const override; + bool colon() const { return m_colon; } +}; +class AstDpiExport final : public AstNode { + // We could put an AstNodeFTaskRef instead of the verilog function name, + // however we're not *calling* it, so that seems somehow wrong. + // (Probably AstNodeFTaskRef should be renamed AstNodeFTaskCall and have-a AstNodeFTaskRef) +private: + string m_name; // Name of function + string m_cname; // Name of function on c side +public: + AstDpiExport(FileLine* fl, const string& vname, const string& cname) + : ASTGEN_SUPER_DpiExport(fl) + , m_name{vname} + , m_cname{cname} {} + ASTGEN_MEMBERS_DpiExport; + string name() const override { return m_name; } + void name(const string& name) override { m_name = name; } + string cname() const { return m_cname; } + void cname(const string& cname) { m_cname = cname; } +}; +class AstElabDisplay final : public AstNode { + // Parents: stmtlist + // @astgen op1 := fmtp : List[AstSFormatF] +private: + VDisplayType m_displayType; + +public: + inline AstElabDisplay(FileLine* fl, VDisplayType dispType, AstNode* exprsp); + ASTGEN_MEMBERS_ElabDisplay; + const char* broken() const override { + BROKEN_RTN(!fmtp()); + return nullptr; + } + string verilogKwd() const override { return (string("$") + string(displayType().ascii())); } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering + bool isOutputter() const override { return true; } // SPECIAL: $display makes output + bool isUnlikely() const override { return true; } + bool same(const AstNode* samep) const override { + return displayType() == static_cast(samep)->displayType(); + } + int instrCount() const override { return INSTR_COUNT_PLI; } + VDisplayType displayType() const { return m_displayType; } + void displayType(VDisplayType type) { m_displayType = type; } +}; +class AstEmpty final : public AstNode { + // Represents something missing, e.g. a missing argument in FOREACH +public: + explicit AstEmpty(FileLine* fl) + : ASTGEN_SUPER_Empty(fl) {} + ASTGEN_MEMBERS_Empty; + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstExecGraph final : public AstNode { + // For parallel execution, this node contains a dependency graph. Each + // vertex in the graph is an ExecMTask, which contains a body for the + // mtask (an AstMTaskBody), which contains sequentially executed statements. + // + // The AstMTaskBody nodes are also children of this node, so we can visit + // them without traversing the graph. + // + // @astgen op1 := mTaskBodiesp : List[AstMTaskBody] + // In later phases, the statements that start the parallel execution + // @astgen op2 := stmtsp : List[AstNode] + V3Graph* const m_depGraphp; // contains ExecMTask vertices + const string m_name; // Name of this AstExecGraph (for uniqueness at code generation) + +public: + explicit AstExecGraph(FileLine* fl, const string& name); + ASTGEN_MEMBERS_ExecGraph; + ~AstExecGraph() override; + const char* broken() const override { + BROKEN_RTN(!m_depGraphp); + return nullptr; + } + string name() const override { return m_name; } + V3Graph* depGraphp() { return m_depGraphp; } + const V3Graph* depGraphp() const { return m_depGraphp; } +}; +class AstImplicit final : public AstNode { + // Create implicit wires and do nothing else, for gates that are ignored + // Parents: MODULE + // @astgen op1 := exprsp : List[AstNode] +public: + AstImplicit(FileLine* fl, AstNode* exprsp) + : ASTGEN_SUPER_Implicit(fl) { + this->addExprsp(exprsp); + } + ASTGEN_MEMBERS_Implicit; +}; +class AstInitArray final : public AstNode { + // Set a var to a map of values + // The list of initsp() is not relevant + // If default is specified, the vector may be sparse, and not provide each value. + // Key values are C++ array style, with lo() at index 0 + // Parents: ASTVAR::init() + // @astgen op1 := defaultp : Optional[AstNode] // Default, if sparse + // @astgen op2 := initsp : List[AstNode] // Initial value expressions + // +public: + using KeyItemMap = std::map; + +private: + KeyItemMap m_map; // Node value for each array index +public: + AstInitArray(FileLine* fl, AstNodeDType* newDTypep, AstNode* defaultp) + : ASTGEN_SUPER_InitArray(fl) { + dtypep(newDTypep); + this->defaultp(defaultp); + } + ASTGEN_MEMBERS_InitArray; + void dump(std::ostream& str) const override; + const char* broken() const override; + void cloneRelink() override; + bool hasDType() const override { return true; } + bool same(const AstNode* samep) const override { + // Only works if exact same children, instead should override comparison + // of children list, and instead use map-vs-map key/value compare + return m_map == static_cast(samep)->m_map; + } + void addValuep(AstNode* newp) { addIndexValuep(m_map.size(), newp); } + const KeyItemMap& map() const { return m_map; } + void addIndexValuep(uint64_t index, AstNode* newp); + AstNode* getIndexValuep(uint64_t index) const; + AstNode* getIndexDefaultedValuep(uint64_t index) const; +}; +class AstInitItem final : public AstNode { + // Container for a item in an init array + // This container is present so that the value underneath may get replaced with a new nodep + // and the upper AstInitArray's map will remain correct (pointing to this InitItem) + // @astgen op1 := valuep : AstNode +public: + // Parents: INITARRAY + AstInitItem(FileLine* fl, AstNode* valuep) + : ASTGEN_SUPER_InitItem(fl) { + this->valuep(valuep); + } + ASTGEN_MEMBERS_InitItem; + bool maybePointedTo() const override { return true; } + bool hasDType() const override { return false; } // See valuep()'s dtype instead +}; +class AstIntfRef final : public AstNode { + // An interface reference +private: + string m_name; // Name of the reference +public: + AstIntfRef(FileLine* fl, const string& name) + : ASTGEN_SUPER_IntfRef(fl) + , m_name{name} {} + string name() const override { return m_name; } + ASTGEN_MEMBERS_IntfRef; +}; +class AstMTaskBody final : public AstNode { + // Hold statements for each MTask + // @astgen op1 := stmtsp : List[AstNode] + ExecMTask* m_execMTaskp = nullptr; + +public: + explicit AstMTaskBody(FileLine* fl) + : ASTGEN_SUPER_MTaskBody(fl) {} + ASTGEN_MEMBERS_MTaskBody; + const char* broken() const override { + BROKEN_RTN(!m_execMTaskp); + return nullptr; + } + void addStmtsFirstp(AstNode* nodep) { + if (stmtsp()) { + stmtsp()->addHereThisAsNext(nodep); + } else { + addStmtsp(nodep); + } + } + ExecMTask* execMTaskp() const { return m_execMTaskp; } + void execMTaskp(ExecMTask* execMTaskp) { m_execMTaskp = execMTaskp; } + void dump(std::ostream& str = std::cout) const override; +}; +class AstModport final : public AstNode { + // A modport in an interface + // @astgen op1 := varsp : List[AstNode] + string m_name; // Name of the modport +public: + AstModport(FileLine* fl, const string& name, AstNode* varsp) + : ASTGEN_SUPER_Modport(fl) + , m_name{name} { + this->addVarsp(varsp); + } + string name() const override { return m_name; } + bool maybePointedTo() const override { return true; } + ASTGEN_MEMBERS_Modport; +}; +class AstModportFTaskRef final : public AstNode { + // An import/export referenced under a modport + // The storage for the function itself is inside the + // interface/instantiator, thus this is a reference + // PARENT: AstModport +private: + string m_name; // Name of the variable referenced + bool m_export; // Type of the function (import/export) + AstNodeFTask* m_ftaskp = nullptr; // Link to the function +public: + AstModportFTaskRef(FileLine* fl, const string& name, bool isExport) + : ASTGEN_SUPER_ModportFTaskRef(fl) + , m_name{name} + , m_export{isExport} {} + ASTGEN_MEMBERS_ModportFTaskRef; + const char* broken() const override; + void cloneRelink() override; + void dump(std::ostream& str) const override; + string name() const override { return m_name; } + bool isImport() const { return !m_export; } + bool isExport() const { return m_export; } + AstNodeFTask* ftaskp() const { return m_ftaskp; } // [After Link] Pointer to variable + void ftaskp(AstNodeFTask* ftaskp) { m_ftaskp = ftaskp; } +}; +class AstModportVarRef final : public AstNode { + // A input/output/etc variable referenced under a modport + // The storage for the variable itself is inside the interface, thus this is a reference + // PARENT: AstModport +private: + string m_name; // Name of the variable referenced + VDirection m_direction; // Direction of the variable (in/out) + AstVar* m_varp = nullptr; // Link to the actual Var +public: + AstModportVarRef(FileLine* fl, const string& name, VDirection::en direction) + : ASTGEN_SUPER_ModportVarRef(fl) + , m_name{name} + , m_direction{direction} {} + ASTGEN_MEMBERS_ModportVarRef; + const char* broken() const override; + void cloneRelink() override; + void dump(std::ostream& str) const override; + string name() const override { return m_name; } + void direction(const VDirection& flag) { m_direction = flag; } + VDirection direction() const { return m_direction; } + AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable + void varp(AstVar* varp) { m_varp = varp; } +}; +class AstNetlist final : public AstNode { + // All modules are under this single top node. + // Parents: none + // Children: MODULEs & CFILEs + // @astgen op1 := modulesp : List[AstNodeModule] + // @astgen op2 := filesp : List[AstNodeFile] + // @astgen op3 := miscsp : List[AstNode] + + AstTypeTable* const m_typeTablep; // Reference to top type table, for faster lookup + AstConstPool* const m_constPoolp; // Reference to constant pool, for faster lookup + AstPackage* m_dollarUnitPkgp = nullptr; // $unit + AstCFunc* m_evalp = nullptr; // The '_eval' function + AstVarScope* m_dpiExportTriggerp = nullptr; // The DPI export trigger variable + AstTopScope* m_topScopep = nullptr; // The singleton AstTopScope under the top module + VTimescale m_timeunit; // Global time unit + VTimescale m_timeprecision; // Global time precision + bool m_changeRequest = false; // Have _change_request method + bool m_timescaleSpecified = false; // Input HDL specified timescale + uint32_t m_nextFreeMTaskID = 1; // Next unique MTask ID within netlist + // starts at 1 so 0 means no MTask ID + uint32_t m_nextFreeMTaskProfilingID = 0; // Next unique ID to use for PGO +public: + AstNetlist(); + ASTGEN_MEMBERS_Netlist; + const char* broken() const override; + void cloneRelink() override { V3ERROR_NA; } + string name() const override { return "$root"; } + void dump(std::ostream& str) const override; + AstNodeModule* topModulep() const { // Top module in hierarchy + return modulesp(); // First one in the list, for now + } + AstTypeTable* typeTablep() { return m_typeTablep; } + void changeRequest(bool specified) { m_changeRequest = specified; } + bool changeRequest() const { return m_changeRequest; } + AstConstPool* constPoolp() { return m_constPoolp; } + AstPackage* dollarUnitPkgp() const { return m_dollarUnitPkgp; } + AstPackage* dollarUnitPkgAddp(); + AstCFunc* evalp() const { return m_evalp; } + void evalp(AstCFunc* evalp) { m_evalp = evalp; } + AstVarScope* dpiExportTriggerp() const { return m_dpiExportTriggerp; } + void dpiExportTriggerp(AstVarScope* varScopep) { m_dpiExportTriggerp = varScopep; } + AstTopScope* topScopep() const { return m_topScopep; } + void createTopScope(AstScope* scopep); + VTimescale timeunit() const { return m_timeunit; } + void timeunit(const VTimescale& value) { m_timeunit = value; } + VTimescale timeprecision() const { return m_timeprecision; } + void timeInit() { + m_timeunit = v3Global.opt.timeDefaultUnit(); + m_timeprecision = v3Global.opt.timeDefaultPrec(); + } + void timeprecisionMerge(FileLine*, const VTimescale& value); + void timescaleSpecified(bool specified) { m_timescaleSpecified = specified; } + bool timescaleSpecified() const { return m_timescaleSpecified; } + uint32_t allocNextMTaskID() { return m_nextFreeMTaskID++; } + uint32_t allocNextMTaskProfilingID() { return m_nextFreeMTaskProfilingID++; } + uint32_t usedMTaskProfilingIDs() const { return m_nextFreeMTaskProfilingID; } +}; +class AstPackageExport final : public AstNode { +private: + // A package export declaration + string m_name; + AstPackage* m_packagep; // Package hierarchy +public: + AstPackageExport(FileLine* fl, AstPackage* packagep, const string& name) + : ASTGEN_SUPER_PackageExport(fl) + , m_name{name} + , m_packagep{packagep} {} + ASTGEN_MEMBERS_PackageExport; + const char* broken() const override; + void cloneRelink() override; + void dump(std::ostream& str) const override; + string name() const override { return m_name; } + AstPackage* packagep() const { return m_packagep; } + void packagep(AstPackage* nodep) { m_packagep = nodep; } +}; +class AstPackageExportStarStar final : public AstNode { + // A package export *::* declaration +public: + // cppcheck-suppress noExplicitConstructor + AstPackageExportStarStar(FileLine* fl) + : ASTGEN_SUPER_PackageExportStarStar(fl) {} + ASTGEN_MEMBERS_PackageExportStarStar; +}; +class AstPackageImport final : public AstNode { +private: + // A package import declaration + string m_name; + AstPackage* m_packagep; // Package hierarchy +public: + AstPackageImport(FileLine* fl, AstPackage* packagep, const string& name) + : ASTGEN_SUPER_PackageImport(fl) + , m_name{name} + , m_packagep{packagep} {} + ASTGEN_MEMBERS_PackageImport; + const char* broken() const override; + void cloneRelink() override; + void dump(std::ostream& str) const override; + string name() const override { return m_name; } + AstPackage* packagep() const { return m_packagep; } + void packagep(AstPackage* nodep) { m_packagep = nodep; } +}; +class AstParseRef final : public AstNode { + // A reference to a variable, function or task + // We don't know which at parse time due to bison constraints + // The link stages will replace this with AstVarRef, or AstTaskRef, etc. + // Parents: math|stmt + // @astgen op1 := lhsp : Optional[AstNode] + // @astgen op2 := ftaskrefp : Optional[AstNodeFTaskRef] + + VParseRefExp m_expect; // Type we think it should resolve to + string m_name; + +public: + AstParseRef(FileLine* fl, VParseRefExp expect, const string& name, AstNode* lhsp = nullptr, + AstNodeFTaskRef* ftaskrefp = nullptr) + : ASTGEN_SUPER_ParseRef(fl) + , m_expect{expect} + , m_name{name} { + this->lhsp(lhsp); + this->ftaskrefp(ftaskrefp); + } + ASTGEN_MEMBERS_ParseRef; + void dump(std::ostream& str) const override; + string name() const override { return m_name; } // * = Var name + bool same(const AstNode* samep) const override { + const AstParseRef* const asamep = static_cast(samep); + return (expect() == asamep->expect() && m_name == asamep->m_name); + } + void name(const string& name) override { m_name = name; } + VParseRefExp expect() const { return m_expect; } + void expect(VParseRefExp exp) { m_expect = exp; } +}; +class AstPin final : public AstNode { + // A port or parameter assignment on an instantiaton + // @astgen op1 := exprp : Optional[AstNode] // Expression connected (nullptr if unconnected) +private: + int m_pinNum; // Pin number + string m_name; // Pin name, or "" for number based interconnect + AstVar* m_modVarp = nullptr; // Input/output this pin connects to on submodule. + AstParamTypeDType* m_modPTypep = nullptr; // Param type this pin connects to on submodule. + bool m_param = false; // Pin connects to parameter + bool m_svImplicit = false; // Pin is SystemVerilog .name'ed +public: + AstPin(FileLine* fl, int pinNum, const string& name, AstNode* exprp) + : ASTGEN_SUPER_Pin(fl) + , m_pinNum{pinNum} + , m_name{name} { + this->exprp(exprp); + } + inline AstPin(FileLine* fl, int pinNum, AstVarRef* varname, AstNode* exprp); + ASTGEN_MEMBERS_Pin; + void dump(std::ostream& str) const override; + const char* broken() const override; + string name() const override { return m_name; } // * = Pin name, ""=go by number + void name(const string& name) override { m_name = name; } + string prettyOperatorName() const override; + bool dotStar() const { return name() == ".*"; } // Fake name for .* connections until linked + int pinNum() const { return m_pinNum; } + AstVar* modVarp() const { return m_modVarp; } // [After Link] Pointer to variable + void modVarp(AstVar* nodep) { m_modVarp = nodep; } + // [After Link] Pointer to variable + AstParamTypeDType* modPTypep() const { return m_modPTypep; } + void modPTypep(AstParamTypeDType* nodep) { m_modPTypep = nodep; } + bool param() const { return m_param; } + void param(bool flag) { m_param = flag; } + bool svImplicit() const { return m_svImplicit; } + void svImplicit(bool flag) { m_svImplicit = flag; } +}; +class AstPort final : public AstNode { + // A port (in/out/inout) on a module + // @astgen op1 := exprp : Optional[AstNode] // Expression connected to port + const int m_pinNum; // Pin number + const string m_name; // Name of pin +public: + AstPort(FileLine* fl, int pinnum, const string& name) + : ASTGEN_SUPER_Port(fl) + , m_pinNum{pinnum} + , m_name{name} {} + ASTGEN_MEMBERS_Port; + string name() const override { return m_name; } // * = Port name + int pinNum() const { return m_pinNum; } // * = Pin number, for order based instantiation +}; +class AstPragma final : public AstNode { + const VPragmaType m_pragType; // Type of pragma +public: + // Pragmas don't result in any output code, they're just flags that affect + // other processing in verilator. + AstPragma(FileLine* fl, VPragmaType pragType) + : ASTGEN_SUPER_Pragma(fl) + , m_pragType{pragType} {} + ASTGEN_MEMBERS_Pragma; + VPragmaType pragType() const { return m_pragType; } // *=type of the pragma + bool isPredictOptimizable() const override { return false; } + bool same(const AstNode* samep) const override { + return pragType() == static_cast(samep)->pragType(); + } +}; +class AstPropClocked final : public AstNode { + // A clocked property + // Parents: ASSERT|COVER (property) + // Children: SENITEM, Properties + // @astgen op1 := sensesp : Optional[AstSenItem] + // @astgen op2 := disablep : Optional[AstNode] + // @astgen op3 := propp : AstNode +public: + AstPropClocked(FileLine* fl, AstSenItem* sensesp, AstNode* disablep, AstNode* propp) + : ASTGEN_SUPER_PropClocked(fl) { + this->sensesp(sensesp); + this->disablep(disablep); + this->propp(propp); + } + ASTGEN_MEMBERS_PropClocked; + bool hasDType() const override { + return true; + } // Used under Cover, which expects a bool child +}; +class AstPull final : public AstNode { + // @astgen op1 := lhsp : AstNode + + const bool m_direction; + +public: + AstPull(FileLine* fl, AstNode* lhsp, bool direction) + : ASTGEN_SUPER_Pull(fl) + , m_direction{direction} { + this->lhsp(lhsp); + } + ASTGEN_MEMBERS_Pull; + bool same(const AstNode* samep) const override { + return direction() == static_cast(samep)->direction(); + } + uint32_t direction() const { return (uint32_t)m_direction; } +}; +class AstSFormatF final : public AstNode { + // Convert format to string, generally under an AstDisplay or AstSFormat + // Also used as "real" function for /*verilator sformat*/ functions + // @astgen op1 := exprsp : List[AstNode] + // @astgen op2 := scopeNamep : Optional[AstScopeName] + string m_text; + const bool m_hidden; // Under display, etc + bool m_hasFormat; // Has format code + const char m_missingArgChar; // Format code when argument without format, 'h'/'o'/'b' + VTimescale m_timeunit; // Parent module time unit +public: + class NoFormat {}; + AstSFormatF(FileLine* fl, const string& text, bool hidden, AstNode* exprsp, + char missingArgChar = 'd') + : ASTGEN_SUPER_SFormatF(fl) + , m_text{text} + , m_hidden{hidden} + , m_hasFormat{true} + , m_missingArgChar{missingArgChar} { + dtypeSetString(); + addExprsp(exprsp); + } + AstSFormatF(FileLine* fl, NoFormat, AstNode* exprsp, char missingArgChar = 'd', + bool hidden = true) + : ASTGEN_SUPER_SFormatF(fl) + , m_text{""} + , m_hidden{hidden} + , m_hasFormat{false} + , m_missingArgChar{missingArgChar} { + dtypeSetString(); + addExprsp(exprsp); + } + ASTGEN_MEMBERS_SFormatF; + string name() const override { return m_text; } + int instrCount() const override { return INSTR_COUNT_PLI; } + bool hasDType() const override { return true; } + bool same(const AstNode* samep) const override { + return text() == static_cast(samep)->text(); + } + string verilogKwd() const override { return "$sformatf"; } + string text() const { return m_text; } // * = Text to display + void text(const string& text) { m_text = text; } + bool formatScopeTracking() const { // Track scopeNamep(); Ok if false positive + return (name().find("%m") != string::npos || name().find("%M") != string::npos); + } + bool hidden() const { return m_hidden; } + void hasFormat(bool flag) { m_hasFormat = flag; } + bool hasFormat() const { return m_hasFormat; } + char missingArgChar() const { return m_missingArgChar; } + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } +}; +class AstScope final : public AstNode { + // A particular usage of a cell + // Parents: MODULE + // Children: NODEBLOCK + // @astgen op1 := varsp : List[AstVarScope] + // @astgen op2 := blocksp : List[AstNode] // Logic blocks/AstActive/AstCFunc + // @astgen op3 := finalClksp : List[AstNode] + + // An AstScope->name() is special: . indicates an uninlined scope, __DOT__ an inlined scope + string m_name; // Name + AstScope* const m_aboveScopep; // Scope above this one in the hierarchy (nullptr if top) + AstCell* const m_aboveCellp; // Cell above this in the hierarchy (nullptr if top) + AstNodeModule* const m_modp; // Module scope corresponds to +public: + AstScope(FileLine* fl, AstNodeModule* modp, const string& name, AstScope* aboveScopep, + AstCell* aboveCellp) + : ASTGEN_SUPER_Scope(fl) + , m_name{name} + , m_aboveScopep{aboveScopep} + , m_aboveCellp{aboveCellp} + , m_modp{modp} {} + ASTGEN_MEMBERS_Scope; + void cloneRelink() override; + const char* broken() const override; + bool maybePointedTo() const override { return true; } + string name() const override { return m_name; } // * = Scope name + void name(const string& name) override { m_name = name; } + void dump(std::ostream& str) const override; + string nameDotless() const; + string nameVlSym() const { return ((string("vlSymsp->")) + nameDotless()); } + AstNodeModule* modp() const { return m_modp; } + AstScope* aboveScopep() const { return m_aboveScopep; } + AstCell* aboveCellp() const { return m_aboveCellp; } + bool isTop() const { return aboveScopep() == nullptr; } // At top of hierarchy +}; +class AstSelLoopVars final : public AstNode { + // Parser only concept "[id, id, id]" for a foreach statement + // Unlike normal selects elements is a list + // @astgen op1 := fromp : AstNode + // @astgen op2 := elementsp : List[AstNode] +public: + AstSelLoopVars(FileLine* fl, AstNode* fromp, AstNode* elementsp) + : ASTGEN_SUPER_SelLoopVars(fl) { + this->fromp(fromp); + this->addElementsp(elementsp); + } + ASTGEN_MEMBERS_SelLoopVars; + bool same(const AstNode* /*samep*/) const override { return true; } + bool maybePointedTo() const override { return false; } +}; +class AstSenItem final : public AstNode { + // Parents: SENTREE + // @astgen op1 := sensp : Optional[AstNode] // Sensitivity expression + VEdgeType m_edgeType; // Edge type +public: + class Combo {}; // for creator type-overload selection + class Illegal {}; // for creator type-overload selection + class Initial {}; // for creator type-overload selection + class Settle {}; // for creator type-overload selection + class Never {}; // for creator type-overload selection + AstSenItem(FileLine* fl, VEdgeType edgeType, AstNode* senp) + : ASTGEN_SUPER_SenItem(fl) + , m_edgeType{edgeType} { + this->sensp(senp); + } + AstSenItem(FileLine* fl, Combo) + : ASTGEN_SUPER_SenItem(fl) + , m_edgeType{VEdgeType::ET_COMBO} {} + AstSenItem(FileLine* fl, Illegal) + : ASTGEN_SUPER_SenItem(fl) + , m_edgeType{VEdgeType::ET_ILLEGAL} {} + AstSenItem(FileLine* fl, Initial) + : ASTGEN_SUPER_SenItem(fl) + , m_edgeType{VEdgeType::ET_INITIAL} {} + AstSenItem(FileLine* fl, Settle) + : ASTGEN_SUPER_SenItem(fl) + , m_edgeType{VEdgeType::ET_SETTLE} {} + AstSenItem(FileLine* fl, Never) + : ASTGEN_SUPER_SenItem(fl) + , m_edgeType{VEdgeType::ET_NEVER} {} + ASTGEN_MEMBERS_SenItem; + void dump(std::ostream& str) const override; + bool same(const AstNode* samep) const override { + return edgeType() == static_cast(samep)->edgeType(); + } + VEdgeType edgeType() const { return m_edgeType; } // * = Posedge/negedge + void edgeType(VEdgeType type) { + m_edgeType = type; + editCountInc(); + } + AstNodeVarRef* varrefp() const { return VN_CAST(sensp(), NodeVarRef); } + // + bool isClocked() const { return edgeType().clockedStmt(); } + bool isCombo() const { return edgeType() == VEdgeType::ET_COMBO; } + bool isInitial() const { return edgeType() == VEdgeType::ET_INITIAL; } + bool isIllegal() const { return edgeType() == VEdgeType::ET_ILLEGAL; } + bool isSettle() const { return edgeType() == VEdgeType::ET_SETTLE; } + bool isNever() const { return edgeType() == VEdgeType::ET_NEVER; } + bool hasVar() const { return !(isCombo() || isInitial() || isSettle() || isNever()); } +}; +class AstSenTree final : public AstNode { + // A sensitivity list + // @astgen op1 := sensesp : List[AstSenItem] + bool m_multi = false; // Created from combo logic by ORing multiple clock domains +public: + AstSenTree(FileLine* fl, AstSenItem* sensesp) + : ASTGEN_SUPER_SenTree(fl) { + this->addSensesp(sensesp); + } + ASTGEN_MEMBERS_SenTree; + void dump(std::ostream& str) const override; + bool maybePointedTo() const override { return true; } + bool isMulti() const { return m_multi; } + void multi(bool flag) { m_multi = true; } + // METHODS + bool hasClocked() const; // Includes a clocked statement + bool hasSettle() const; // Includes a SETTLE SenItem + bool hasInitial() const; // Includes a INITIAL SenItem + bool hasCombo() const; // Includes a COMBO SenItem +}; +class AstSplitPlaceholder final : public AstNode { +public: + // Dummy node used within V3Split; never exists outside of V3Split. + explicit AstSplitPlaceholder(FileLine* fl) + : ASTGEN_SUPER_SplitPlaceholder(fl) {} + ASTGEN_MEMBERS_SplitPlaceholder; +}; +class AstStrengthSpec final : public AstNode { +private: + VStrength m_s0; // Drive 0 strength + VStrength m_s1; // Drive 1 strength + +public: + AstStrengthSpec(FileLine* fl, VStrength s0, VStrength s1) + : ASTGEN_SUPER_StrengthSpec(fl) + , m_s0{s0} + , m_s1{s1} {} + + ASTGEN_MEMBERS_StrengthSpec; + VStrength strength0() { return m_s0; } + VStrength strength1() { return m_s1; } + void dump(std::ostream& str) const override; +}; +class AstTopScope final : public AstNode { + // A singleton, held under the top level AstModule. Holds the top level + // AstScope, and after V3ActiveTop, the global list of AstSenTrees (list of + // unique sensitivity lists). + // + // @astgen op1 := senTreesp : List[AstSenTree] // Globally unique sensitivity lists + // @astgen op2 := scopep : AstScope // The AstScope of the top-leveL + + friend class AstNetlist; // Only the AstNetlist can create one + AstTopScope(FileLine* fl, AstScope* ascopep) + : ASTGEN_SUPER_TopScope(fl) { + this->scopep(ascopep); + } + +public: + ASTGEN_MEMBERS_TopScope; + bool maybePointedTo() const override { return true; } +}; +class AstTypeTable final : public AstNode { + // Container for hash of standard data types + // @astgen op1 := typesp : List[AstNodeDType] + AstEmptyQueueDType* m_emptyQueuep = nullptr; + AstQueueDType* m_queueIndexp = nullptr; + AstVoidDType* m_voidp = nullptr; + AstBasicDType* m_basicps[VBasicDTypeKwd::_ENUM_MAX]{}; + // + using DetailedMap = std::map; + DetailedMap m_detailedMap; + +public: + explicit AstTypeTable(FileLine* fl); + ASTGEN_MEMBERS_TypeTable; + bool maybePointedTo() const override { return true; } + const char* broken() const override { + BROKEN_RTN(m_emptyQueuep && !m_emptyQueuep->brokeExists()); + BROKEN_RTN(m_queueIndexp && !m_queueIndexp->brokeExists()); + BROKEN_RTN(m_voidp && !m_voidp->brokeExists()); + return nullptr; + } + void cloneRelink() override { V3ERROR_NA; } + AstBasicDType* findBasicDType(FileLine* fl, VBasicDTypeKwd kwd); + AstBasicDType* findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd, int width, int widthMin, + VSigning numeric); + AstBasicDType* findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd, const VNumRange& range, + int widthMin, VSigning numeric); + AstBasicDType* findInsertSameDType(AstBasicDType* nodep); + AstEmptyQueueDType* findEmptyQueueDType(FileLine* fl); + AstQueueDType* findQueueIndexDType(FileLine* fl); + AstVoidDType* findVoidDType(FileLine* fl); + void clearCache(); + void repairCache(); + void dump(std::ostream& str = std::cout) const override; +}; +class AstTypedef final : public AstNode { + // @astgen op1 := childDTypep : Optional[AstNodeDType] + // @astgen op4 := attrsp : List[AstNode] // Attributes during early parse + + string m_name; + bool m_attrPublic = false; + string m_tag; // Holds the string of the verilator tag -- used in XML output. +public: + AstTypedef(FileLine* fl, const string& name, AstNode* attrsp, VFlagChildDType, + AstNodeDType* dtp) + : ASTGEN_SUPER_Typedef(fl) + , m_name{name} { + childDTypep(dtp); // Only for parser + addAttrsp(attrsp); + dtypep(nullptr); // V3Width will resolve + } + ASTGEN_MEMBERS_Typedef; + void dump(std::ostream& str) const override; + AstNodeDType* getChildDTypep() const override { return childDTypep(); } + virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } + // METHODS + string name() const override { return m_name; } + bool maybePointedTo() const override { return true; } + bool hasDType() const override { return true; } + void name(const string& flag) override { m_name = flag; } + bool attrPublic() const { return m_attrPublic; } + void attrPublic(bool flag) { m_attrPublic = flag; } + void tag(const string& text) override { m_tag = text; } + string tag() const override { return m_tag; } +}; +class AstTypedefFwd final : public AstNode { + // Forward declaration of a type; stripped after netlist parsing is complete +private: + string m_name; + +public: + AstTypedefFwd(FileLine* fl, const string& name) + : ASTGEN_SUPER_TypedefFwd(fl) + , m_name{name} {} + ASTGEN_MEMBERS_TypedefFwd; + // METHODS + string name() const override { return m_name; } + bool maybePointedTo() const override { return true; } +}; +class AstUdpTable final : public AstNode { + // @astgen op1 := linesp : List[AstUdpTableLine] +public: + AstUdpTable(FileLine* fl, AstUdpTableLine* linesp) + : ASTGEN_SUPER_UdpTable(fl) { + this->addLinesp(linesp); + } + ASTGEN_MEMBERS_UdpTable; +}; +class AstUdpTableLine final : public AstNode { + string m_text; + +public: + AstUdpTableLine(FileLine* fl, const string& text) + : ASTGEN_SUPER_UdpTableLine(fl) + , m_text{text} {} + ASTGEN_MEMBERS_UdpTableLine; + string name() const override { return m_text; } + string text() const { return m_text; } +}; +class AstUnlinkedRef final : public AstNode { + // As-of-yet unlinkable Ref + // @astgen op1 := refp : AstNode + // @astgen op2 := cellrefp : AstNode + + string m_name; // Var name // TODO: There is no way to access this, fix or remove +public: + AstUnlinkedRef(FileLine* fl, AstNode* refp, const string& name, AstNode* cellrefp) + : ASTGEN_SUPER_UnlinkedRef(fl) + , m_name{name} { + this->refp(refp); + this->cellrefp(cellrefp); + } + ASTGEN_MEMBERS_UnlinkedRef; +}; +class AstVar final : public AstNode { + // A variable (in/out/wire/reg/param) inside a module + // + // @astgen op1 := childDTypep : Optional[AstNodeDType] + // @astgen op2 := delayp : Optional[AstNode] // Net delay + // Initial value that never changes (static const), or constructor argument for + // MTASKSTATE variables + // @astgen op3 := valuep : Optional[AstNode] + // @astgen op4 := attrsp : List[AstNode] // Attributes during early parse + + string m_name; // Name of variable + string m_origName; // Original name before dot addition + string m_tag; // Holds the string of the verilator tag -- used in XML output. + VVarType m_varType; // Type of variable + VDirection m_direction; // Direction input/output etc + VDirection m_declDirection; // Declared direction input/output etc + VBasicDTypeKwd m_declKwd; // Keyword at declaration time + VLifetime m_lifetime; // Lifetime + VVarAttrClocker m_attrClocker; + MTaskIdSet m_mtaskIds; // MTaskID's that read or write this var + int m_pinNum = 0; // For XML, if non-zero the connection pin number + bool m_ansi : 1; // ANSI port list variable (for dedup check) + bool m_declTyped : 1; // Declared as type (for dedup check) + bool m_tristate : 1; // Inout or triwire or trireg + bool m_primaryIO : 1; // In/out to top level (or directly assigned from same) + bool m_sc : 1; // SystemC variable + bool m_scClocked : 1; // SystemC sc_clk<> needed + bool m_scSensitive : 1; // SystemC sensitive() needed + bool m_sigPublic : 1; // User C code accesses this signal or is top signal + bool m_sigModPublic : 1; // User C code accesses this signal and module + bool m_sigUserRdPublic : 1; // User C code accesses this signal, read only + bool m_sigUserRWPublic : 1; // User C code accesses this signal, read-write + bool m_usedClock : 1; // Signal used as a clock + bool m_usedParam : 1; // Parameter is referenced (on link; later signals not setup) + bool m_usedLoopIdx : 1; // Variable subject of for unrolling + bool m_funcLocal : 1; // Local variable for a function + bool m_funcReturn : 1; // Return variable for a function + bool m_attrClockEn : 1; // User clock enable attribute + bool m_attrScBv : 1; // User force bit vector attribute + bool m_attrIsolateAssign : 1; // User isolate_assignments attribute + bool m_attrSFormat : 1; // User sformat attribute + bool m_attrSplitVar : 1; // declared with split_var metacomment + bool m_fileDescr : 1; // File descriptor + bool m_isRand : 1; // Random variable + bool m_isConst : 1; // Table contains constant data + bool m_isContinuously : 1; // Ever assigned continuously (for force/release) + bool m_hasStrengthAssignment : 1; // Is on LHS of assignment with strength specifier + bool m_isStatic : 1; // Static C variable (for Verilog see instead isAutomatic) + bool m_isPulldown : 1; // Tri0 + bool m_isPullup : 1; // Tri1 + bool m_isIfaceParent : 1; // dtype is reference to interface present in this module + bool m_isDpiOpenArray : 1; // DPI import open array + bool m_isHideLocal : 1; // Verilog local + bool m_isHideProtected : 1; // Verilog protected + bool m_noReset : 1; // Do not do automated reset/randomization + bool m_noSubst : 1; // Do not substitute out references + bool m_overridenParam : 1; // Overridden parameter by #(...) or defparam + bool m_trace : 1; // Trace this variable + bool m_isLatched : 1; // Not assigned in all control paths of combo always + bool m_isForceable : 1; // May be forced/released externally from user C code + + void init() { + m_ansi = false; + m_declTyped = false; + m_tristate = false; + m_primaryIO = false; + m_sc = false; + m_scClocked = false; + m_scSensitive = false; + m_usedClock = false; + m_usedParam = false; + m_usedLoopIdx = false; + m_sigPublic = false; + m_sigModPublic = false; + m_sigUserRdPublic = false; + m_sigUserRWPublic = false; + m_funcLocal = false; + m_funcReturn = false; + m_attrClockEn = false; + m_attrScBv = false; + m_attrIsolateAssign = false; + m_attrSFormat = false; + m_attrSplitVar = false; + m_fileDescr = false; + m_isRand = false; + m_isConst = false; + m_isContinuously = false; + m_hasStrengthAssignment = false; + m_isStatic = false; + m_isPulldown = false; + m_isPullup = false; + m_isIfaceParent = false; + m_isDpiOpenArray = false; + m_isHideLocal = false; + m_isHideProtected = false; + m_noReset = false; + m_noSubst = false; + m_overridenParam = false; + m_trace = false; + m_isLatched = false; + m_isForceable = false; + m_attrClocker = VVarAttrClocker::CLOCKER_UNKNOWN; + } + +public: + AstVar(FileLine* fl, VVarType type, const string& name, VFlagChildDType, AstNodeDType* dtp) + : ASTGEN_SUPER_Var(fl) + , m_name{name} + , m_origName{name} { + init(); + combineType(type); + childDTypep(dtp); // Only for parser + dtypep(nullptr); // V3Width will resolve + if (dtp->basicp()) { + m_declKwd = dtp->basicp()->keyword(); + } else { + m_declKwd = VBasicDTypeKwd::LOGIC; + } + } + AstVar(FileLine* fl, VVarType type, const string& name, AstNodeDType* dtp) + : ASTGEN_SUPER_Var(fl) + , m_name{name} + , m_origName{name} { + init(); + combineType(type); + UASSERT(dtp, "AstVar created with no dtype"); + dtypep(dtp); + if (dtp->basicp()) { + m_declKwd = dtp->basicp()->keyword(); + } else { + m_declKwd = VBasicDTypeKwd::LOGIC; + } + } + AstVar(FileLine* fl, VVarType type, const string& name, VFlagLogicPacked, int wantwidth) + : ASTGEN_SUPER_Var(fl) + , m_name{name} + , m_origName{name} { + init(); + combineType(type); + dtypeSetLogicSized(wantwidth, VSigning::UNSIGNED); + m_declKwd = VBasicDTypeKwd::LOGIC; + } + AstVar(FileLine* fl, VVarType type, const string& name, VFlagBitPacked, int wantwidth) + : ASTGEN_SUPER_Var(fl) + , m_name{name} + , m_origName{name} { + init(); + combineType(type); + dtypeSetBitSized(wantwidth, VSigning::UNSIGNED); + m_declKwd = VBasicDTypeKwd::BIT; + } + AstVar(FileLine* fl, VVarType type, const string& name, AstVar* examplep) + : ASTGEN_SUPER_Var(fl) + , m_name{name} + , m_origName{name} { + init(); + combineType(type); + if (examplep->childDTypep()) childDTypep(examplep->childDTypep()->cloneTree(true)); + dtypeFrom(examplep); + m_declKwd = examplep->declKwd(); + } + ASTGEN_MEMBERS_Var; + void dump(std::ostream& str) const override; + string name() const override { return m_name; } // * = Var name + bool hasDType() const override { return true; } + bool maybePointedTo() const override { return true; } + string origName() const override { return m_origName; } // * = Original name + void origName(const string& name) { m_origName = name; } + VVarType varType() const { return m_varType; } // * = Type of variable + void direction(const VDirection& flag) { + m_direction = flag; + if (m_direction == VDirection::INOUT) m_tristate = true; + } + VDirection direction() const { return m_direction; } + bool isIO() const { return m_direction != VDirection::NONE; } + void declDirection(const VDirection& flag) { m_declDirection = flag; } + VDirection declDirection() const { return m_declDirection; } + void varType(VVarType type) { m_varType = type; } + void varType2Out() { + m_tristate = false; + m_direction = VDirection::OUTPUT; + } + void varType2In() { + m_tristate = false; + m_direction = VDirection::INPUT; + } + VBasicDTypeKwd declKwd() const { return m_declKwd; } + string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv + // Return C /*public*/ type for argument: bool, uint32_t, uint64_t, etc. + string cPubArgType(bool named, bool forReturn) const; + string dpiArgType(bool named, bool forReturn) const; // Return DPI-C type for argument + string dpiTmpVarType(const string& varName) const; + // Return Verilator internal type for argument: CData, SData, IData, WData + string vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc = "", + bool asRef = false) const; + string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc + string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc + string vlPropDecl(const string& propName) const; // Return VerilatorVarProps declaration + void combineType(VVarType type); + AstNodeDType* getChildDTypep() const override { return childDTypep(); } + AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } + // (Slow) recurse down to find basic data type (Note don't need virtual - + // AstVar isn't a NodeDType) + AstBasicDType* basicp() const { return subDTypep()->basicp(); } + virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } + void ansi(bool flag) { m_ansi = flag; } + void declTyped(bool flag) { m_declTyped = flag; } + void attrClockEn(bool flag) { m_attrClockEn = flag; } + void attrClocker(VVarAttrClocker flag) { m_attrClocker = flag; } + void attrFileDescr(bool flag) { m_fileDescr = flag; } + void attrScClocked(bool flag) { m_scClocked = flag; } + void attrScBv(bool flag) { m_attrScBv = flag; } + void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; } + void attrSFormat(bool flag) { m_attrSFormat = flag; } + void attrSplitVar(bool flag) { m_attrSplitVar = flag; } + void usedClock(bool flag) { m_usedClock = flag; } + void usedParam(bool flag) { m_usedParam = flag; } + void usedLoopIdx(bool flag) { m_usedLoopIdx = flag; } + void sigPublic(bool flag) { m_sigPublic = flag; } + void sigModPublic(bool flag) { m_sigModPublic = flag; } + void sigUserRdPublic(bool flag) { + m_sigUserRdPublic = flag; + if (flag) sigPublic(true); + } + void sigUserRWPublic(bool flag) { + m_sigUserRWPublic = flag; + if (flag) sigUserRdPublic(true); + } + void sc(bool flag) { m_sc = flag; } + void scSensitive(bool flag) { m_scSensitive = flag; } + void primaryIO(bool flag) { m_primaryIO = flag; } + void isRand(bool flag) { m_isRand = flag; } + void isConst(bool flag) { m_isConst = flag; } + void isContinuously(bool flag) { m_isContinuously = flag; } + void isStatic(bool flag) { m_isStatic = flag; } + void isIfaceParent(bool flag) { m_isIfaceParent = flag; } + void funcLocal(bool flag) { m_funcLocal = flag; } + void funcReturn(bool flag) { m_funcReturn = flag; } + void hasStrengthAssignment(bool flag) { m_hasStrengthAssignment = flag; } + bool hasStrengthAssignment() { return m_hasStrengthAssignment; } + void isDpiOpenArray(bool flag) { m_isDpiOpenArray = flag; } + bool isDpiOpenArray() const { return m_isDpiOpenArray; } + bool isHideLocal() const { return m_isHideLocal; } + void isHideLocal(bool flag) { m_isHideLocal = flag; } + bool isHideProtected() const { return m_isHideProtected; } + void isHideProtected(bool flag) { m_isHideProtected = flag; } + void noReset(bool flag) { m_noReset = flag; } + bool noReset() const { return m_noReset; } + void noSubst(bool flag) { m_noSubst = flag; } + bool noSubst() const { return m_noSubst; } + void overriddenParam(bool flag) { m_overridenParam = flag; } + bool overriddenParam() const { return m_overridenParam; } + void trace(bool flag) { m_trace = flag; } + void isLatched(bool flag) { m_isLatched = flag; } + bool isForceable() const { return m_isForceable; } + void setForceable() { m_isForceable = true; } + // METHODS + void name(const string& name) override { m_name = name; } + void tag(const string& text) override { m_tag = text; } + string tag() const override { return m_tag; } + bool isAnsi() const { return m_ansi; } + bool isContinuously() const { return m_isContinuously; } + bool isDeclTyped() const { return m_declTyped; } + bool isInoutish() const { return m_direction.isInoutish(); } + bool isNonOutput() const { return m_direction.isNonOutput(); } + bool isReadOnly() const { return m_direction.isReadOnly(); } + bool isWritable() const { return m_direction.isWritable(); } + bool isTristate() const { return m_tristate; } + bool isPrimaryIO() const { return m_primaryIO; } + bool isPrimaryInish() const { return isPrimaryIO() && isNonOutput(); } + bool isIfaceRef() const { return (varType() == VVarType::IFACEREF); } + bool isIfaceParent() const { return m_isIfaceParent; } + bool isSignal() const { return varType().isSignal(); } + bool isNet() const { return varType().isNet(); } + bool isTemp() const { return varType().isTemp(); } + bool isToggleCoverable() const { + return ((isIO() || isSignal()) + && (isIO() || isBitLogic()) + // Wrapper would otherwise duplicate wrapped module's coverage + && !isSc() && !isPrimaryIO() && !isConst() && !isDouble() && !isString()); + } + bool isClassMember() const { return varType() == VVarType::MEMBER; } + bool isStatementTemp() const { return (varType() == VVarType::STMTTEMP); } + bool isXTemp() const { return (varType() == VVarType::XTEMP); } + bool isParam() const { + return (varType() == VVarType::LPARAM || varType() == VVarType::GPARAM); + } + bool isGParam() const { return (varType() == VVarType::GPARAM); } + bool isGenVar() const { return (varType() == VVarType::GENVAR); } + bool isBitLogic() const { + AstBasicDType* bdtypep = basicp(); + return bdtypep && bdtypep->isBitLogic(); + } + bool isUsedClock() const { return m_usedClock; } + bool isUsedParam() const { return m_usedParam; } + bool isUsedLoopIdx() const { return m_usedLoopIdx; } + bool isSc() const { return m_sc; } + bool isScQuad() const; + bool isScBv() const; + bool isScUint() const; + bool isScBigUint() const; + bool isScSensitive() const { return m_scSensitive; } + bool isSigPublic() const; + bool isSigModPublic() const { return m_sigModPublic; } + bool isSigUserRdPublic() const { return m_sigUserRdPublic; } + bool isSigUserRWPublic() const { return m_sigUserRWPublic; } + bool isTrace() const { return m_trace; } + bool isRand() const { return m_isRand; } + bool isConst() const { return m_isConst; } + bool isStatic() const { return m_isStatic; } + bool isLatched() const { return m_isLatched; } + bool isFuncLocal() const { return m_funcLocal; } + bool isFuncReturn() const { return m_funcReturn; } + bool isPullup() const { return m_isPullup; } + bool isPulldown() const { return m_isPulldown; } + bool attrClockEn() const { return m_attrClockEn; } + bool attrScBv() const { return m_attrScBv; } + bool attrFileDescr() const { return m_fileDescr; } + bool attrScClocked() const { return m_scClocked; } + bool attrSFormat() const { return m_attrSFormat; } + bool attrSplitVar() const { return m_attrSplitVar; } + bool attrIsolateAssign() const { return m_attrIsolateAssign; } + VVarAttrClocker attrClocker() const { return m_attrClocker; } + string verilogKwd() const override; + void lifetime(const VLifetime& flag) { m_lifetime = flag; } + VLifetime lifetime() const { return m_lifetime; } + void propagateAttrFrom(AstVar* fromp) { + // This is getting connected to fromp; keep attributes + // Note the method below too + if (fromp->attrClockEn()) attrClockEn(true); + if (fromp->attrFileDescr()) attrFileDescr(true); + if (fromp->attrIsolateAssign()) attrIsolateAssign(true); + if (fromp->isContinuously()) isContinuously(true); + } + bool gateMultiInputOptimizable() const { + // Ok to gate optimize; must return false if propagateAttrFrom would do anything + return (!attrClockEn() && !isUsedClock()); + } + void combineType(AstVar* typevarp) { + // This is same as typevarp (for combining input & reg decls) + // "this" is the input var. typevarp is the reg var. + propagateAttrFrom(typevarp); + combineType(typevarp->varType()); + if (typevarp->isSigPublic()) sigPublic(true); + if (typevarp->isSigModPublic()) sigModPublic(true); + if (typevarp->isSigUserRdPublic()) sigUserRdPublic(true); + if (typevarp->isSigUserRWPublic()) sigUserRWPublic(true); + if (typevarp->attrScClocked()) attrScClocked(true); + } + void inlineAttrReset(const string& name) { + if (direction() == VDirection::INOUT && varType() == VVarType::WIRE) { + m_varType = VVarType::TRIWIRE; + } + m_direction = VDirection::NONE; + m_name = name; + } + static AstVar* scVarRecurse(AstNode* nodep); + void addProducingMTaskId(int id) { m_mtaskIds.insert(id); } + void addConsumingMTaskId(int id) { m_mtaskIds.insert(id); } + const MTaskIdSet& mtaskIds() const { return m_mtaskIds; } + void pinNum(int id) { m_pinNum = id; } + int pinNum() const { return m_pinNum; } +}; +class AstVarScope final : public AstNode { + // A particular scoped usage of a variable + // That is, as a module is used under multiple cells, we get a different + // varscope for each var in the module + // Parents: MODULE + // Children: none +private: + AstScope* m_scopep; // Scope variable is underneath + AstVar* m_varp; // [AfterLink] Pointer to variable itself + bool m_circular : 1; // Used in circular ordering dependency, need change detect + bool m_trace : 1; // Tracing is turned on for this scope +public: + AstVarScope(FileLine* fl, AstScope* scopep, AstVar* varp) + : ASTGEN_SUPER_VarScope(fl) + , m_scopep{scopep} + , m_varp{varp} { + UASSERT_OBJ(scopep, fl, "Scope must be non-null"); + UASSERT_OBJ(varp, fl, "Var must be non-null"); + m_circular = false; + m_trace = true; + dtypeFrom(varp); + } + ASTGEN_MEMBERS_VarScope; + void cloneRelink() override { + if (m_varp && m_varp->clonep()) { + m_varp = m_varp->clonep(); + UASSERT(m_scopep->clonep(), "No clone cross link: " << this); + m_scopep = m_scopep->clonep(); + } + } + const char* broken() const override { + BROKEN_RTN(m_varp && !m_varp->brokeExists()); + BROKEN_RTN(m_scopep && !m_scopep->brokeExists()); + return nullptr; + } + bool maybePointedTo() const override { return true; } + string name() const override { return scopep()->name() + "->" + varp()->name(); } + void dump(std::ostream& str) const override; + bool hasDType() const override { return true; } + AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable + AstScope* scopep() const { return m_scopep; } // Pointer to scope it's under + void scopep(AstScope* nodep) { m_scopep = nodep; } + bool isCircular() const { return m_circular; } + void circular(bool flag) { m_circular = flag; } + bool isTrace() const { return m_trace; } + void trace(bool flag) { m_trace = flag; } +}; + +// === AstNodeBlock === +class AstBegin final : public AstNodeBlock { + // A Begin/end named block, only exists shortly after parsing until linking + // Parents: statement + // @astgen op2 := genforp : Optional[AstNode] + + bool m_generate; // Underneath a generate + const bool m_implied; // Not inserted by user +public: + // Node that puts name into the output stream + AstBegin(FileLine* fl, const string& name, AstNode* stmtsp, bool generate = false, + bool implied = false) + : ASTGEN_SUPER_Begin(fl, name, stmtsp) + , m_generate{generate} + , m_implied{implied} {} + ASTGEN_MEMBERS_Begin; + void dump(std::ostream& str) const override; + void generate(bool flag) { m_generate = flag; } + bool generate() const { return m_generate; } + bool implied() const { return m_implied; } +}; +class AstFork final : public AstNodeBlock { + // A fork named block + // Parents: statement + // Children: statements +private: + VJoinType m_joinType; // Join keyword type +public: + // Node that puts name into the output stream + AstFork(FileLine* fl, const string& name, AstNode* stmtsp) + : ASTGEN_SUPER_Fork(fl, name, stmtsp) {} + ASTGEN_MEMBERS_Fork; + void dump(std::ostream& str) const override; + VJoinType joinType() const { return m_joinType; } + void joinType(const VJoinType& flag) { m_joinType = flag; } +}; + +// === AstNodeFTask === +class AstFunc final : public AstNodeFTask { + // A function inside a module +public: + AstFunc(FileLine* fl, const string& name, AstNode* stmtp, AstNode* fvarp) + : ASTGEN_SUPER_Func(fl, name, stmtp) { + this->fvarp(fvarp); + } + ASTGEN_MEMBERS_Func; + bool hasDType() const override { return true; } +}; +class AstTask final : public AstNodeFTask { + // A task inside a module +public: + AstTask(FileLine* fl, const string& name, AstNode* stmtp) + : ASTGEN_SUPER_Task(fl, name, stmtp) {} + ASTGEN_MEMBERS_Task; +}; + +// === AstNodeFile === +class AstCFile final : public AstNodeFile { + // C++ output file + // Parents: NETLIST +private: + bool m_slow : 1; ///< Compile w/o optimization + bool m_source : 1; ///< Source file (vs header file) + bool m_support : 1; ///< Support file (non systemc) +public: + AstCFile(FileLine* fl, const string& name) + : ASTGEN_SUPER_CFile(fl, name) + , m_slow{false} + , m_source{false} + , m_support{false} {} + ASTGEN_MEMBERS_CFile; + void dump(std::ostream& str = std::cout) const override; + bool slow() const { return m_slow; } + void slow(bool flag) { m_slow = flag; } + bool source() const { return m_source; } + void source(bool flag) { m_source = flag; } + bool support() const { return m_support; } + void support(bool flag) { m_support = flag; } +}; +class AstVFile final : public AstNodeFile { + // Verilog output file + // Parents: NETLIST +public: + AstVFile(FileLine* fl, const string& name) + : ASTGEN_SUPER_VFile(fl, name) {} + ASTGEN_MEMBERS_VFile; + void dump(std::ostream& str = std::cout) const override; +}; + +// === AstNodeModule === +class AstClass final : public AstNodeModule { + // @astgen op4 := extendsp : Optional[AstClassExtends] + // TYPES + using MemberNameMap = std::map; + // MEMBERS + MemberNameMap m_members; // Members or method children + AstClassPackage* m_classOrPackagep = nullptr; // Class package this is under + bool m_virtual = false; // Virtual class + bool m_extended = false; // Is extension or extended by other classes + void insertCache(AstNode* nodep); + +public: + AstClass(FileLine* fl, const string& name) + : ASTGEN_SUPER_Class(fl, name) {} + ASTGEN_MEMBERS_Class; + string verilogKwd() const override { return "class"; } + bool maybePointedTo() const override { return true; } + void dump(std::ostream& str) const override; + const char* broken() const override; + void cloneRelink() override; + bool timescaleMatters() const override { return false; } + AstClassPackage* classOrPackagep() const { return m_classOrPackagep; } + void classOrPackagep(AstClassPackage* classpackagep) { m_classOrPackagep = classpackagep; } + AstNode* membersp() const { return stmtsp(); } + void addMembersp(AstNode* nodep) { + insertCache(nodep); + addStmtsp(nodep); + } + void clearCache() { m_members.clear(); } + void repairCache(); + AstNode* findMember(const string& name) const { + const auto it = m_members.find(name); + return (it == m_members.end()) ? nullptr : it->second; + } + bool isExtended() const { return m_extended; } + void isExtended(bool flag) { m_extended = flag; } + bool isVirtual() const { return m_virtual; } + void isVirtual(bool flag) { m_virtual = flag; } + // Return true if this class is an extension of base class (SLOW) + // Accepts nullptrs + static bool isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp); +}; +class AstClassPackage final : public AstNodeModule { + // The static information portion of a class (treated similarly to a package) + AstClass* m_classp + = nullptr; // Class package this is under (weak pointer, hard link is other way) +public: + AstClassPackage(FileLine* fl, const string& name) + : ASTGEN_SUPER_ClassPackage(fl, name) {} + ASTGEN_MEMBERS_ClassPackage; + string verilogKwd() const override { return "classpackage"; } + const char* broken() const override; + void cloneRelink() override; + bool timescaleMatters() const override { return false; } + AstClass* classp() const { return m_classp; } + void classp(AstClass* classp) { m_classp = classp; } +}; +class AstIface final : public AstNodeModule { + // A module declaration +public: + AstIface(FileLine* fl, const string& name) + : ASTGEN_SUPER_Iface(fl, name) {} + ASTGEN_MEMBERS_Iface; + // Interfaces have `timescale applicability but lots of code seems to + // get false warnings if we enable this + string verilogKwd() const override { return "interface"; } + bool timescaleMatters() const override { return false; } +}; +class AstModule final : public AstNodeModule { + // A module declaration +private: + const bool m_isProgram; // Module represents a program +public: + AstModule(FileLine* fl, const string& name, bool program = false) + : ASTGEN_SUPER_Module(fl, name) + , m_isProgram{program} {} + ASTGEN_MEMBERS_Module; + string verilogKwd() const override { return m_isProgram ? "program" : "module"; } + bool timescaleMatters() const override { return true; } +}; +class AstNotFoundModule final : public AstNodeModule { + // A missing module declaration +public: + AstNotFoundModule(FileLine* fl, const string& name) + : ASTGEN_SUPER_NotFoundModule(fl, name) {} + ASTGEN_MEMBERS_NotFoundModule; + string verilogKwd() const override { return "/*not-found-*/ module"; } + bool timescaleMatters() const override { return false; } +}; +class AstPackage final : public AstNodeModule { + // A package declaration +public: + AstPackage(FileLine* fl, const string& name) + : ASTGEN_SUPER_Package(fl, name) {} + ASTGEN_MEMBERS_Package; + string verilogKwd() const override { return "package"; } + bool timescaleMatters() const override { return !isDollarUnit(); } + static string dollarUnitName() { return AstNode::encodeName("$unit"); } + bool isDollarUnit() const { return name() == dollarUnitName(); } +}; +class AstPrimitive final : public AstNodeModule { + // A primitive declaration +public: + AstPrimitive(FileLine* fl, const string& name) + : ASTGEN_SUPER_Primitive(fl, name) {} + ASTGEN_MEMBERS_Primitive; + string verilogKwd() const override { return "primitive"; } + bool timescaleMatters() const override { return false; } +}; + +// === AstNodePreSel === +class AstSelBit final : public AstNodePreSel { + // Single bit range extraction, perhaps with non-constant selection or array selection + // Gets replaced during link with AstArraySel or AstSel +public: + AstSelBit(FileLine* fl, AstNode* fromp, AstNode* bitp) + : ASTGEN_SUPER_SelBit(fl, fromp, bitp, nullptr) { + UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, + "not coded to create after dtypes resolved"); + } + ASTGEN_MEMBERS_SelBit; + AstNode* bitp() const { return rhsp(); } +}; +class AstSelExtract final : public AstNodePreSel { + // Range extraction, gets replaced with AstSel +public: + AstSelExtract(FileLine* fl, AstNode* fromp, AstNode* msbp, AstNode* lsbp) + : ASTGEN_SUPER_SelExtract(fl, fromp, msbp, lsbp) {} + ASTGEN_MEMBERS_SelExtract; + AstNode* leftp() const { return rhsp(); } + AstNode* rightp() const { return thsp(); } +}; +class AstSelMinus final : public AstNodePreSel { + // -: range extraction, perhaps with non-constant selection + // Gets replaced during link with AstSel +public: + AstSelMinus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp) + : ASTGEN_SUPER_SelMinus(fl, fromp, bitp, widthp) {} + ASTGEN_MEMBERS_SelMinus; + AstNode* bitp() const { return rhsp(); } + AstNode* widthp() const { return thsp(); } +}; +class AstSelPlus final : public AstNodePreSel { + // +: range extraction, perhaps with non-constant selection + // Gets replaced during link with AstSel +public: + AstSelPlus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp) + : ASTGEN_SUPER_SelPlus(fl, fromp, bitp, widthp) {} + ASTGEN_MEMBERS_SelPlus; + AstNode* bitp() const { return rhsp(); } + AstNode* widthp() const { return thsp(); } +}; + +// === AstNodeProcedure === +class AstAlways final : public AstNodeProcedure { + // @astgen op1 := sensesp : Optional[AstSenTree] // Sensitivity list iff clocked + const VAlwaysKwd m_keyword; + +public: + AstAlways(FileLine* fl, VAlwaysKwd keyword, AstSenTree* sensesp, AstNode* stmtsp) + : ASTGEN_SUPER_Always(fl, stmtsp) + , m_keyword{keyword} { + this->sensesp(sensesp); + } + ASTGEN_MEMBERS_Always; + // + void dump(std::ostream& str) const override; + VAlwaysKwd keyword() const { return m_keyword; } +}; +class AstAlwaysPost final : public AstNodeProcedure { + // Like always but post assignments for memory assignment IFs + // @astgen op1 := sensesp : Optional[AstSenTree] // Sensitivity list iff clocked +public: + AstAlwaysPost(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp) + : ASTGEN_SUPER_AlwaysPost(fl, stmtsp) { + this->sensesp(sensesp); + } + ASTGEN_MEMBERS_AlwaysPost; +}; +class AstAlwaysPostponed final : public AstNodeProcedure { + // Like always but postponement scheduling region + +public: + AstAlwaysPostponed(FileLine* fl, AstNode* stmtsp) + : ASTGEN_SUPER_AlwaysPostponed(fl, stmtsp) {} + ASTGEN_MEMBERS_AlwaysPostponed; +}; +class AstFinal final : public AstNodeProcedure { +public: + AstFinal(FileLine* fl, AstNode* stmtsp) + : ASTGEN_SUPER_Final(fl, stmtsp) {} + ASTGEN_MEMBERS_Final; +}; +class AstInitial final : public AstNodeProcedure { +public: + AstInitial(FileLine* fl, AstNode* stmtsp) + : ASTGEN_SUPER_Initial(fl, stmtsp) {} + ASTGEN_MEMBERS_Initial; +}; +class AstInitialAutomatic final : public AstNodeProcedure { + // Automatic variable initialization + // That is, it runs every function start, or class construction +public: + AstInitialAutomatic(FileLine* fl, AstNode* stmtsp) + : ASTGEN_SUPER_InitialAutomatic(fl, stmtsp) {} + ASTGEN_MEMBERS_InitialAutomatic; +}; +class AstInitialStatic final : public AstNodeProcedure { + // Static variable initialization + // That is, it runs at the beginning of simulation, before 'initial' blocks +public: + AstInitialStatic(FileLine* fl, AstNode* stmtsp) + : ASTGEN_SUPER_InitialStatic(fl, stmtsp) {} + ASTGEN_MEMBERS_InitialStatic; +}; + +// === AstNodeRange === +class AstBracketRange final : public AstNodeRange { + // Parser only concept "[lhsp]", a AstUnknownRange, QueueRange or Range, + // unknown until lhsp type is determined + // @astgen op1 := elementsp : AstNode +public: + AstBracketRange(FileLine* fl, AstNode* elementsp) + : ASTGEN_SUPER_BracketRange(fl) { + this->elementsp(elementsp); + } + ASTGEN_MEMBERS_BracketRange; + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } + bool same(const AstNode* /*samep*/) const override { return true; } + // Will be removed in V3Width, which relies on this + // being a child not a dtype pointed node + bool maybePointedTo() const override { return false; } +}; +class AstRange final : public AstNodeRange { + // Range specification, for use under variables and cells + // @astgen op1 := leftp : AstNode + // @astgen op2 := rightp : AstNode +public: + AstRange(FileLine* fl, AstNode* leftp, AstNode* rightp) + : ASTGEN_SUPER_Range(fl) { + this->leftp(leftp); + this->rightp(rightp); + } + inline AstRange(FileLine* fl, int left, int right); + inline AstRange(FileLine* fl, const VNumRange& range); + ASTGEN_MEMBERS_Range; + inline int leftConst() const; + inline int rightConst() const; + int hiConst() const { + const int l = leftConst(); + const int r = rightConst(); + return l > r ? l : r; + } + int loConst() const { + const int l = leftConst(); + const int r = rightConst(); + return l > r ? r : l; + } + int elementsConst() const { return hiConst() - loConst() + 1; } + bool littleEndian() const { return leftConst() < rightConst(); } + void dump(std::ostream& str) const override; + virtual string emitC() { V3ERROR_NA_RETURN(""); } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstUnsizedRange final : public AstNodeRange { + // Unsized range specification, for open arrays +public: + explicit AstUnsizedRange(FileLine* fl) + : ASTGEN_SUPER_UnsizedRange(fl) {} + ASTGEN_MEMBERS_UnsizedRange; + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual string emitVerilog() { return "[]"; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstWildcardRange final : public AstNodeRange { + // Wildcard range specification, for wildcard index type associative arrays +public: + explicit AstWildcardRange(FileLine* fl) + : ASTGEN_SUPER_WildcardRange(fl) {} + ASTGEN_MEMBERS_WildcardRange; + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual string emitVerilog() { return "[*]"; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; + +// === AstNodeStmt === +class AstAlwaysPublic final : public AstNodeStmt { + // "Fake" sensitivity created by /*verilator public_flat_rw @(edgelist)*/ + // Body statements are just AstVarRefs to the public signals + // @astgen op1 := sensesp : List[AstSenTree] + // @astgen op2 := stmtsp : List[AstNode] +public: + AstAlwaysPublic(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp) + : ASTGEN_SUPER_AlwaysPublic(fl) { + addSensesp(sensesp); + addStmtsp(stmtsp); + } + ASTGEN_MEMBERS_AlwaysPublic; + bool same(const AstNode* /*samep*/) const override { return true; } + // Special accessors + bool isJustOneBodyStmt() const { return stmtsp() && !stmtsp()->nextp(); } + bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); } +}; +class AstBreak final : public AstNodeStmt { +public: + explicit AstBreak(FileLine* fl) + : ASTGEN_SUPER_Break(fl) {} + ASTGEN_MEMBERS_Break; + string verilogKwd() const override { return "break"; } + bool isBrancher() const override { + return true; // SPECIAL: We don't process code after breaks + } +}; +class AstCMethodHard final : public AstNodeStmt { + // A reference to a "C" hardcoded member task (or function) + // PARENTS: stmt/math + // Not all calls are statments vs math. AstNodeStmt needs isStatement() to deal. + // @astgen op1 := fromp : AstNode // Subject of method call + // @astgen op2 := pinsp : List[AstNode] // Arguments +private: + string m_name; // Name of method + bool m_pure = false; // Pure optimizable +public: + AstCMethodHard(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name, + AstNode* pinsp = nullptr) + : ASTGEN_SUPER_CMethodHard(fl, false) + , m_name{name} { + // TODO: this constructor is exactly the same as the other, bar the ignored tag argument + this->fromp(fromp); + this->addPinsp(pinsp); + dtypep(nullptr); // V3Width will resolve + } + AstCMethodHard(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp = nullptr) + : ASTGEN_SUPER_CMethodHard(fl, false) + , m_name{name} { + this->fromp(fromp); + this->addPinsp(pinsp); + } + ASTGEN_MEMBERS_CMethodHard; + string name() const override { return m_name; } // * = Var name + bool hasDType() const override { return true; } + void name(const string& name) override { m_name = name; } + bool same(const AstNode* samep) const override { + const AstCMethodHard* asamep = static_cast(samep); + return (m_name == asamep->m_name); + } + bool isPure() const override { return m_pure; } + void pure(bool flag) { m_pure = flag; } + void makeStatement() { + statement(true); + dtypeSetVoid(); + } +}; +class AstCReset final : public AstNodeStmt { + // Reset variable at startup + // @astgen op1 := varrefp : AstVarRef +public: + AstCReset(FileLine* fl, AstVarRef* varrefp) + : ASTGEN_SUPER_CReset(fl) { + this->varrefp(varrefp); + } + ASTGEN_MEMBERS_CReset; + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstCReturn final : public AstNodeStmt { + // C++ return from a function + // @astgen op1 := lhsp : AstNode +public: + AstCReturn(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_CReturn(fl) { + this->lhsp(lhsp); + } + ASTGEN_MEMBERS_CReturn; + int instrCount() const override { return widthInstrs(); } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstCStmt final : public AstNodeStmt { + // Emit C statement + // @astgen op1 := exprsp : List[AstNode] +public: + AstCStmt(FileLine* fl, AstNode* exprsp) + : ASTGEN_SUPER_CStmt(fl) { + this->addExprsp(exprsp); + } + inline AstCStmt(FileLine* fl, const string& textStmt); + ASTGEN_MEMBERS_CStmt; + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstChangeDet final : public AstNodeStmt { + // A comparison to determine change detection, common & must be fast. + // @astgen op1 := lhsp : Optional[AstNode] + // @astgen op2 := rhsp : Optional[AstNode] +public: + // Null lhs+rhs used to indicate change needed with no spec vars + AstChangeDet(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_ChangeDet(fl) { + this->lhsp(lhsp); + this->rhsp(rhsp); + } + ASTGEN_MEMBERS_ChangeDet; + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + int instrCount() const override { return widthInstrs() * 2; } // xor, or/logor + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstComment final : public AstNodeStmt { + // Some comment to put into the output stream + // Parents: {statement list} + const bool m_showAt; // Show "at " + const string m_name; // Text of comment +public: + AstComment(FileLine* fl, const string& name, bool showAt = false) + : ASTGEN_SUPER_Comment(fl) + , m_showAt{showAt} + , m_name{name} {} + ASTGEN_MEMBERS_Comment; + string name() const override { return m_name; } // * = Text + bool same(const AstNode* samep) const override { return true; } // Ignore name in comments + virtual bool showAt() const { return m_showAt; } +}; +class AstContinue final : public AstNodeStmt { +public: + explicit AstContinue(FileLine* fl) + : ASTGEN_SUPER_Continue(fl) {} + ASTGEN_MEMBERS_Continue; + string verilogKwd() const override { return "continue"; } + bool isBrancher() const override { + return true; // SPECIAL: We don't process code after breaks + } +}; +class AstCoverDecl final : public AstNodeStmt { + // Coverage analysis point declaration + // Parents: {statement list} + // Children: none +private: + AstCoverDecl* m_dataDeclp = nullptr; // [After V3CoverageJoin] Pointer to duplicate + // declaration to get data from instead + string m_page; + string m_text; + string m_hier; + string m_linescov; + int m_offset; // Offset column numbers to uniq-ify IFs + int m_binNum = 0; // Set by V3EmitCSyms to tell final V3Emit what to increment +public: + AstCoverDecl(FileLine* fl, const string& page, const string& comment, const string& linescov, + int offset) + : ASTGEN_SUPER_CoverDecl(fl) + , m_page{page} + , m_text{comment} + , m_linescov{linescov} + , m_offset{offset} {} + ASTGEN_MEMBERS_CoverDecl; + const char* broken() const override { + BROKEN_RTN(m_dataDeclp && !m_dataDeclp->brokeExists()); + if (m_dataDeclp && m_dataDeclp->m_dataDeclp) { // Avoid O(n^2) accessing + v3fatalSrc("dataDeclp should point to real data, not be a list"); + } + return nullptr; + } + void cloneRelink() override { + if (m_dataDeclp && m_dataDeclp->clonep()) m_dataDeclp = m_dataDeclp->clonep(); + } + void dump(std::ostream& str) const override; + int instrCount() const override { return 1 + 2 * INSTR_COUNT_LD; } + bool maybePointedTo() const override { return true; } + void binNum(int flag) { m_binNum = flag; } + int binNum() const { return m_binNum; } + int offset() const { return m_offset; } + const string& comment() const { return m_text; } // text to insert in code + const string& linescov() const { return m_linescov; } + const string& page() const { return m_page; } + const string& hier() const { return m_hier; } + void hier(const string& flag) { m_hier = flag; } + void comment(const string& flag) { m_text = flag; } + bool same(const AstNode* samep) const override { + const AstCoverDecl* const asamep = static_cast(samep); + return (fileline() == asamep->fileline() && linescov() == asamep->linescov() + && hier() == asamep->hier() && comment() == asamep->comment()); + } + bool isPredictOptimizable() const override { return false; } + void dataDeclp(AstCoverDecl* nodep) { m_dataDeclp = nodep; } + // dataDecl nullptr means "use this one", but often you want "this" to + // indicate to get data from here + AstCoverDecl* dataDeclNullp() const { return m_dataDeclp; } + AstCoverDecl* dataDeclThisp() { return dataDeclNullp() ? dataDeclNullp() : this; } +}; +class AstCoverInc final : public AstNodeStmt { + // Coverage analysis point; increment coverage count + // Parents: {statement list} + // Children: none +private: + AstCoverDecl* m_declp; // [After V3Coverage] Pointer to declaration +public: + AstCoverInc(FileLine* fl, AstCoverDecl* declp) + : ASTGEN_SUPER_CoverInc(fl) + , m_declp{declp} {} + ASTGEN_MEMBERS_CoverInc; + const char* broken() const override { + BROKEN_RTN(!declp()->brokeExists()); + return nullptr; + } + void cloneRelink() override { + if (m_declp->clonep()) m_declp = m_declp->clonep(); + } + void dump(std::ostream& str) const override; + int instrCount() const override { return 1 + 2 * INSTR_COUNT_LD; } + bool same(const AstNode* samep) const override { + return declp() == static_cast(samep)->declp(); + } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isOutputter() const override { return true; } + // but isPure() true + AstCoverDecl* declp() const { return m_declp; } // Where defined +}; +class AstCoverToggle final : public AstNodeStmt { + // Toggle analysis of given signal + // Parents: MODULE + // @astgen op1 := incp : AstCoverInc + // @astgen op2 := origp : AstNode + // @astgen op3 := changep : AstNode +public: + AstCoverToggle(FileLine* fl, AstCoverInc* incp, AstNode* origp, AstNode* changep) + : ASTGEN_SUPER_CoverToggle(fl) { + this->incp(incp); + this->origp(origp); + this->changep(changep); + } + ASTGEN_MEMBERS_CoverToggle; + int instrCount() const override { return 3 + INSTR_COUNT_BRANCH + INSTR_COUNT_LD; } + bool same(const AstNode* /*samep*/) const override { return true; } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return true; } + bool isOutputter() const override { + return false; // Though the AstCoverInc under this is an outputter + } + // but isPure() true +}; +class AstDelay final : public AstNodeStmt { + // Delay statement + // @astgen op1 := lhsp : AstNode // Delay value + // @astgen op2 := stmtsp : List[AstNode] // Statements under delay +public: + AstDelay(FileLine* fl, AstNode* lhsp, AstNode* stmtsp) + : ASTGEN_SUPER_Delay(fl) { + this->lhsp(lhsp); + this->addStmtsp(stmtsp); + } + ASTGEN_MEMBERS_Delay; + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstDisable final : public AstNodeStmt { +private: + string m_name; // Name of block +public: + AstDisable(FileLine* fl, const string& name) + : ASTGEN_SUPER_Disable(fl) + , m_name{name} {} + ASTGEN_MEMBERS_Disable; + string name() const override { return m_name; } // * = Block name + void name(const string& flag) override { m_name = flag; } + bool isBrancher() const override { + return true; // SPECIAL: We don't process code after breaks + } +}; +class AstDisableFork final : public AstNodeStmt { + // A "disable fork" statement +public: + explicit AstDisableFork(FileLine* fl) + : ASTGEN_SUPER_DisableFork(fl) {} + ASTGEN_MEMBERS_DisableFork; +}; +class AstDisplay final : public AstNodeStmt { + // Parents: stmtlist + // @astgen op1 := fmtp : AstSFormatF + // @astgen op2 := filep : Optional[AstNode] // file (must be a VarRef) +private: + VDisplayType m_displayType; + +public: + AstDisplay(FileLine* fl, VDisplayType dispType, const string& text, AstNode* filep, + AstNode* exprsp, char missingArgChar = 'd') + : ASTGEN_SUPER_Display(fl) + , m_displayType{dispType} { + this->fmtp(new AstSFormatF{fl, text, true, exprsp, missingArgChar}); + this->filep(filep); + } + AstDisplay(FileLine* fl, VDisplayType dispType, AstNode* filep, AstNode* exprsp, + char missingArgChar = 'd') + : ASTGEN_SUPER_Display(fl) + , m_displayType{dispType} { + this->fmtp(new AstSFormatF{fl, AstSFormatF::NoFormat(), exprsp, missingArgChar}); + this->filep(filep); + } + ASTGEN_MEMBERS_Display; + void dump(std::ostream& str) const override; + const char* broken() const override { + BROKEN_RTN(!fmtp()); + return nullptr; + } + string verilogKwd() const override { + return (filep() ? string("$f") + string(displayType().ascii()) + : string("$") + string(displayType().ascii())); + } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering + bool isOutputter() const override { return true; } // SPECIAL: $display makes output + bool isUnlikely() const override { return true; } + bool same(const AstNode* samep) const override { + return displayType() == static_cast(samep)->displayType(); + } + int instrCount() const override { return INSTR_COUNT_PLI; } + VDisplayType displayType() const { return m_displayType; } + void displayType(VDisplayType type) { m_displayType = type; } + // * = Add a newline for $display + bool addNewline() const { return displayType().addNewline(); } +}; +class AstDpiExportUpdated final : public AstNodeStmt { + // Denotes that the referenced variable may have been updated via a DPI Export + // @astgen op1 := varRefp : AstVarRef +public: + inline AstDpiExportUpdated(FileLine* fl, AstVarScope* varScopep); + ASTGEN_MEMBERS_DpiExportUpdated; + inline AstVarScope* varScopep() const; +}; +class AstDumpCtl final : public AstNodeStmt { + // $dumpon etc + // Parents: expr + // @astgen op1 := exprp : Optional[AstNode] // Expression based on type of control statement + const VDumpCtlType m_ctlType; // Type of operation +public: + AstDumpCtl(FileLine* fl, VDumpCtlType ctlType, AstNode* exprp = nullptr) + : ASTGEN_SUPER_DumpCtl(fl) + , m_ctlType{ctlType} { + this->exprp(exprp); + } + ASTGEN_MEMBERS_DumpCtl; + string verilogKwd() const override { return ctlType().ascii(); } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isOutputter() const override { return true; } + virtual bool cleanOut() const { return true; } + bool same(const AstNode* /*samep*/) const override { return true; } + VDumpCtlType ctlType() const { return m_ctlType; } +}; +class AstEventControl final : public AstNodeStmt { + // Parents: stmtlist + // @astgen op1 := sensesp : Optional[AstSenTree] + // @astgen op2 := stmtsp : List[AstNode] +public: + AstEventControl(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp) + : ASTGEN_SUPER_EventControl(fl) { + this->sensesp(sensesp); + this->addStmtsp(stmtsp); + } + ASTGEN_MEMBERS_EventControl; + string verilogKwd() const override { return "@(%l) %r"; } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } + bool isOutputter() const override { return false; } + int instrCount() const override { return 0; } +}; +class AstFClose final : public AstNodeStmt { + // Parents: stmtlist + // @astgen op1 := filep : AstNode // file (must be a VarRef) +public: + AstFClose(FileLine* fl, AstNode* filep) + : ASTGEN_SUPER_FClose(fl) { + this->filep(filep); + } + ASTGEN_MEMBERS_FClose; + string verilogKwd() const override { return "$fclose"; } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } + bool isOutputter() const override { return true; } + bool isUnlikely() const override { return true; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstFFlush final : public AstNodeStmt { + // Parents: stmtlist + // @astgen op1 := filep : Optional[AstNode] // file (must be a VarRef) +public: + AstFFlush(FileLine* fl, AstNode* filep) + : ASTGEN_SUPER_FFlush(fl) { + this->filep(filep); + } + ASTGEN_MEMBERS_FFlush; + string verilogKwd() const override { return "$fflush"; } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } + bool isOutputter() const override { return true; } + bool isUnlikely() const override { return true; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstFOpen final : public AstNodeStmt { + // Although a system function in IEEE, here a statement which sets the file pointer (MCD) + // @astgen op1 := filep : AstNode + // @astgen op2 := filenamep : AstNode + // @astgen op3 := modep : AstNode +public: + AstFOpen(FileLine* fl, AstNode* filep, AstNode* filenamep, AstNode* modep) + : ASTGEN_SUPER_FOpen(fl) { + this->filep(filep); + this->filenamep(filenamep); + this->modep(modep); + } + ASTGEN_MEMBERS_FOpen; + string verilogKwd() const override { return "$fopen"; } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } + bool isOutputter() const override { return true; } + bool isUnlikely() const override { return true; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstFOpenMcd final : public AstNodeStmt { + // Although a system function in IEEE, here a statement which sets the file pointer (MCD) + // @astgen op1 := filep : AstNode + // @astgen op2 := filenamep : AstNode +public: + AstFOpenMcd(FileLine* fl, AstNode* filep, AstNode* filenamep) + : ASTGEN_SUPER_FOpenMcd(fl) { + this->filep(filep); + this->filenamep(filenamep); + } + ASTGEN_MEMBERS_FOpenMcd; + string verilogKwd() const override { return "$fopen"; } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } + bool isOutputter() const override { return true; } + bool isUnlikely() const override { return true; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstFinish final : public AstNodeStmt { +public: + explicit AstFinish(FileLine* fl) + : ASTGEN_SUPER_Finish(fl) {} + ASTGEN_MEMBERS_Finish; + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering + bool isOutputter() const override { return true; } // SPECIAL: $display makes output + bool isUnlikely() const override { return true; } + int instrCount() const override { return 0; } // Rarely executes + bool same(const AstNode* samep) const override { return fileline() == samep->fileline(); } +}; +class AstForeach final : public AstNodeStmt { + // @astgen op1 := arrayp : AstNode + // @astgen op2 := stmtsp : List[AstNode] +public: + AstForeach(FileLine* fl, AstNode* arrayp, AstNode* stmtsp) + : ASTGEN_SUPER_Foreach(fl) { + this->arrayp(arrayp); + this->addStmtsp(stmtsp); + } + ASTGEN_MEMBERS_Foreach; + bool isGateOptimizable() const override { return false; } + int instrCount() const override { return INSTR_COUNT_BRANCH; } + bool same(const AstNode* /*samep*/) const override { return true; } + bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); } +}; +class AstJumpBlock final : public AstNodeStmt { + // Block of code including a JumpGo and JumpLabel + // Parents: {statement list} + // Children: {statement list, with JumpGo and JumpLabel below} + // @astgen op1 := stmtsp : List[AstNode] + // @astgen op2 := endStmtsp : List[AstNode] +private: + AstJumpLabel* m_labelp = nullptr; // [After V3Jump] Pointer to declaration + int m_labelNum = 0; // Set by V3EmitCSyms to tell final V3Emit what to increment +public: + // After construction must call ->labelp to associate with appropriate label + AstJumpBlock(FileLine* fl, AstNode* stmtsp) + : ASTGEN_SUPER_JumpBlock(fl) { + this->addStmtsp(stmtsp); + } + const char* broken() const override; + void cloneRelink() override; + ASTGEN_MEMBERS_JumpBlock; + int instrCount() const override { return 0; } + bool maybePointedTo() const override { return true; } + bool same(const AstNode* /*samep*/) const override { return true; } + int labelNum() const { return m_labelNum; } + void labelNum(int flag) { m_labelNum = flag; } + AstJumpLabel* labelp() const { return m_labelp; } + void labelp(AstJumpLabel* labelp) { m_labelp = labelp; } +}; +class AstJumpGo final : public AstNodeStmt { + // Jump point; branch down to a JumpLabel + // No support for backward jumps at present + // Parents: {statement list with JumpBlock above} + // Children: none +private: + AstJumpLabel* m_labelp; // [After V3Jump] Pointer to declaration +public: + AstJumpGo(FileLine* fl, AstJumpLabel* labelp) + : ASTGEN_SUPER_JumpGo(fl) + , m_labelp{labelp} {} + ASTGEN_MEMBERS_JumpGo; + const char* broken() const override; + void cloneRelink() override; + void dump(std::ostream& str) const override; + int instrCount() const override { return INSTR_COUNT_BRANCH; } + bool same(const AstNode* samep) const override { + return labelp() == static_cast(samep)->labelp(); + } + bool isGateOptimizable() const override { return false; } + bool isBrancher() const override { + return true; // SPECIAL: We don't process code after breaks + } + AstJumpLabel* labelp() const { return m_labelp; } +}; +class AstJumpLabel final : public AstNodeStmt { + // Jump point declaration + // Parents: {statement list with JumpBlock above} + // Children: none +private: + AstJumpBlock* m_blockp; // [After V3Jump] Pointer to declaration +public: + AstJumpLabel(FileLine* fl, AstJumpBlock* blockp) + : ASTGEN_SUPER_JumpLabel(fl) + , m_blockp{blockp} {} + ASTGEN_MEMBERS_JumpLabel; + bool maybePointedTo() const override { return true; } + const char* broken() const override { + BROKEN_RTN(!blockp()->brokeExistsAbove()); + BROKEN_RTN(blockp()->labelp() != this); + return nullptr; + } + void cloneRelink() override { + if (m_blockp->clonep()) m_blockp = m_blockp->clonep(); + } + void dump(std::ostream& str) const override; + int instrCount() const override { return 0; } + bool same(const AstNode* samep) const override { + return blockp() == static_cast(samep)->blockp(); + } + AstJumpBlock* blockp() const { return m_blockp; } +}; +class AstMonitorOff final : public AstNodeStmt { + const bool m_off; // Monitor off. Using 0=on allows faster init and comparison + +public: + AstMonitorOff(FileLine* fl, bool off) + : ASTGEN_SUPER_MonitorOff(fl) + , m_off{off} {} + ASTGEN_MEMBERS_MonitorOff; + string verilogKwd() const override { return m_off ? "$monitoroff" : "$monitoron"; } + bool isGateOptimizable() const override { return false; } // Though deleted before opt + bool isPredictOptimizable() const override { return false; } // Though deleted before opt + bool isPure() const override { return false; } // Though deleted before opt + bool isOutputter() const override { return true; } // Though deleted before opt + int instrCount() const override { return INSTR_COUNT_PLI; } + bool same(const AstNode* samep) const override { + return m_off == static_cast(samep)->m_off; + } + bool off() const { return m_off; } +}; +class AstPrintTimeScale final : public AstNodeStmt { + // Parents: stmtlist + string m_name; // Parent module name + VTimescale m_timeunit; // Parent module time unit +public: + explicit AstPrintTimeScale(FileLine* fl) + : ASTGEN_SUPER_PrintTimeScale(fl) {} + ASTGEN_MEMBERS_PrintTimeScale; + void name(const string& name) override { m_name = name; } + string name() const override { return m_name; } // * = Var name + void dump(std::ostream& str) const override; + string verilogKwd() const override { return "$printtimescale"; } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } + bool isOutputter() const override { return true; } + int instrCount() const override { return INSTR_COUNT_PLI; } + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } +}; +class AstRelease final : public AstNodeStmt { + // Procedural 'release' statement + // @astgen op1 := lhsp : AstNode +public: + AstRelease(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_Release(fl) { + this->lhsp(lhsp); + } + ASTGEN_MEMBERS_Release; +}; +class AstRepeat final : public AstNodeStmt { + // @astgen op1 := countp : AstNode + // @astgen op2 := stmtsp : List[AstNode] +public: + AstRepeat(FileLine* fl, AstNode* countp, AstNode* stmtsp) + : ASTGEN_SUPER_Repeat(fl) { + this->countp(countp); + this->addStmtsp(stmtsp); + } + ASTGEN_MEMBERS_Repeat; + bool isGateOptimizable() const override { return false; } // Not relevant - converted to FOR + int instrCount() const override { return INSTR_COUNT_BRANCH; } + bool same(const AstNode* /*samep*/) const override { return true; } + bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); } +}; +class AstReturn final : public AstNodeStmt { + // @astgen op1 := lhsp : Optional[AstNode] +public: + explicit AstReturn(FileLine* fl, AstNode* lhsp = nullptr) + : ASTGEN_SUPER_Return(fl) { + this->lhsp(lhsp); + } + ASTGEN_MEMBERS_Return; + string verilogKwd() const override { return "return"; } + bool isBrancher() const override { + return true; // SPECIAL: We don't process code after breaks + } +}; +class AstSFormat final : public AstNodeStmt { + // Parents: statement container + // @astgen op1 := fmtp : AstSFormatF + // @astgen op2 := lhsp : AstNode +public: + AstSFormat(FileLine* fl, AstNode* lhsp, const string& text, AstNode* exprsp, + char missingArgChar = 'd') + : ASTGEN_SUPER_SFormat(fl) { + this->fmtp(new AstSFormatF{fl, text, true, exprsp, missingArgChar}); + this->lhsp(lhsp); + } + AstSFormat(FileLine* fl, AstNode* lhsp, AstNode* exprsp, char missingArgChar = 'd') + : ASTGEN_SUPER_SFormat(fl) { + this->fmtp(new AstSFormatF{fl, AstSFormatF::NoFormat(), exprsp, missingArgChar}); + this->lhsp(lhsp); + } + ASTGEN_MEMBERS_SFormat; + const char* broken() const override { + BROKEN_RTN(!fmtp()); + return nullptr; + } + string verilogKwd() const override { return "$sformat"; } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return true; } + bool isPure() const override { return true; } + bool isOutputter() const override { return false; } + virtual bool cleanOut() const { return false; } + int instrCount() const override { return INSTR_COUNT_PLI; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstStop final : public AstNodeStmt { +public: + AstStop(FileLine* fl, bool maybe) + : ASTGEN_SUPER_Stop(fl) {} + ASTGEN_MEMBERS_Stop; + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering + bool isOutputter() const override { return true; } // SPECIAL: $display makes output + bool isUnlikely() const override { return true; } + int instrCount() const override { return 0; } // Rarely executes + bool same(const AstNode* samep) const override { return fileline() == samep->fileline(); } +}; +class AstSysFuncAsTask final : public AstNodeStmt { + // Call what is normally a system function (with a return) in a non-return context + // @astgen op1 := lhsp : AstNode +public: + AstSysFuncAsTask(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_SysFuncAsTask(fl) { + this->lhsp(lhsp); + } + ASTGEN_MEMBERS_SysFuncAsTask; + string verilogKwd() const override { return ""; } + bool isGateOptimizable() const override { return true; } + bool isPredictOptimizable() const override { return true; } + bool isPure() const override { return true; } + bool isOutputter() const override { return false; } + int instrCount() const override { return 0; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstSysIgnore final : public AstNodeStmt { + // @astgen op1 := exprsp : List[AstNode] // Expressions to output (???) +public: + AstSysIgnore(FileLine* fl, AstNode* exprsp) + : ASTGEN_SUPER_SysIgnore(fl) { + this->addExprsp(exprsp); + } + ASTGEN_MEMBERS_SysIgnore; + string verilogKwd() const override { return "$ignored"; } + bool isGateOptimizable() const override { return false; } // Though deleted before opt + bool isPredictOptimizable() const override { return false; } // Though deleted before opt + bool isPure() const override { return false; } // Though deleted before opt + bool isOutputter() const override { return true; } // Though deleted before opt + int instrCount() const override { return INSTR_COUNT_PLI; } +}; +class AstSystemT final : public AstNodeStmt { + // $system used as task + // @astgen op1 := lhsp : AstNode +public: + AstSystemT(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER_SystemT(fl) { + this->lhsp(lhsp); + } + ASTGEN_MEMBERS_SystemT; + string verilogKwd() const override { return "$system"; } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } + bool isOutputter() const override { return true; } + bool isUnlikely() const override { return true; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstTimeFormat final : public AstNodeStmt { + // Parents: stmtlist + // @astgen op1 := unitsp : AstNode + // @astgen op2 := precisionp : AstNode + // @astgen op3 := suffixp : AstNode + // @astgen op4 := widthp : AstNode +public: + AstTimeFormat(FileLine* fl, AstNode* unitsp, AstNode* precisionp, AstNode* suffixp, + AstNode* widthp) + : ASTGEN_SUPER_TimeFormat(fl) { + this->unitsp(unitsp); + this->precisionp(precisionp); + this->suffixp(suffixp); + this->widthp(widthp); + } + ASTGEN_MEMBERS_TimeFormat; + string verilogKwd() const override { return "$timeformat"; } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } + bool isOutputter() const override { return true; } + int instrCount() const override { return INSTR_COUNT_PLI; } +}; +class AstTraceDecl final : public AstNodeStmt { + // Trace point declaration + // Separate from AstTraceInc; as a declaration can't be deleted + // Parents: {statement list} + // Expression being traced - Moved to AstTraceInc by V3Trace + // @astgen op1 := valuep : Optional[AstNode] +private: + uint32_t m_code = 0; // Trace identifier code; converted to ASCII by trace routines + const string m_showname; // Name of variable + const VNumRange m_bitRange; // Property of var the trace details + const VNumRange m_arrayRange; // Property of var the trace details + const uint32_t m_codeInc; // Code increment + const VVarType m_varType; // Type of variable (for localparam vs. param) + const VBasicDTypeKwd m_declKwd; // Keyword at declaration time + const VDirection m_declDirection; // Declared direction input/output etc +public: + AstTraceDecl(FileLine* fl, const string& showname, + AstVar* varp, // For input/output state etc + AstNode* valuep, const VNumRange& bitRange, const VNumRange& arrayRange) + : ASTGEN_SUPER_TraceDecl(fl) + , m_showname{showname} + , m_bitRange{bitRange} + , m_arrayRange{arrayRange} + , m_codeInc( + ((arrayRange.ranged() ? arrayRange.elements() : 1) * valuep->dtypep()->widthWords() + * (VL_EDATASIZE / 32))) // A code is always 32-bits + , m_varType{varp->varType()} + , m_declKwd{varp->declKwd()} + , m_declDirection{varp->declDirection()} { + dtypeFrom(valuep); + this->valuep(valuep); + } + void dump(std::ostream& str) const override; + int instrCount() const override { return 100; } // Large... + ASTGEN_MEMBERS_TraceDecl; + string name() const override { return m_showname; } + bool maybePointedTo() const override { return true; } + bool hasDType() const override { return true; } + bool same(const AstNode* samep) const override { return false; } + string showname() const { return m_showname; } // * = Var name + // Details on what we're tracing + uint32_t code() const { return m_code; } + void code(uint32_t code) { m_code = code; } + uint32_t codeInc() const { return m_codeInc; } + const VNumRange& bitRange() const { return m_bitRange; } + const VNumRange& arrayRange() const { return m_arrayRange; } + VVarType varType() const { return m_varType; } + VBasicDTypeKwd declKwd() const { return m_declKwd; } + VDirection declDirection() const { return m_declDirection; } +}; +class AstTraceInc final : public AstNodeStmt { + // Trace point dump + // @astgen op1 := precondsp : List[AstNode] // Statements to emit before this node + // @astgen op2 := valuep : AstNode // Expression being traced (from decl) + +private: + AstTraceDecl* m_declp; // Pointer to declaration + const bool m_full; // Is this a full vs incremental dump + const uint32_t m_baseCode; // Trace code base value in function containing this AstTraceInc + +public: + AstTraceInc(FileLine* fl, AstTraceDecl* declp, bool full, uint32_t baseCode = 0) + : ASTGEN_SUPER_TraceInc(fl) + , m_declp{declp} + , m_full{full} + , m_baseCode{baseCode} { + dtypeFrom(declp); + this->valuep( + declp->valuep()->cloneTree(true)); // TODO: maybe use reference to TraceDecl instead? + } + ASTGEN_MEMBERS_TraceInc; + const char* broken() const override { + BROKEN_RTN(!declp()->brokeExists()); + return nullptr; + } + void cloneRelink() override { + if (m_declp->clonep()) m_declp = m_declp->clonep(); + } + void dump(std::ostream& str) const override; + int instrCount() const override { return 10 + 2 * INSTR_COUNT_LD; } + bool hasDType() const override { return true; } + bool same(const AstNode* samep) const override { + return declp() == static_cast(samep)->declp(); + } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isOutputter() const override { return true; } + // but isPure() true + AstTraceDecl* declp() const { return m_declp; } + bool full() const { return m_full; } + uint32_t baseCode() const { return m_baseCode; } +}; +class AstTracePopNamePrefix final : public AstNodeStmt { + const unsigned m_count; // How many levels to pop +public: + AstTracePopNamePrefix(FileLine* fl, unsigned count) + : ASTGEN_SUPER_TracePopNamePrefix(fl) + , m_count{count} {} + ASTGEN_MEMBERS_TracePopNamePrefix; + bool same(const AstNode* samep) const override { return false; } + unsigned count() const { return m_count; } +}; +class AstTracePushNamePrefix final : public AstNodeStmt { + const string m_prefix; // Prefix to add to signal names +public: + AstTracePushNamePrefix(FileLine* fl, const string& prefix) + : ASTGEN_SUPER_TracePushNamePrefix(fl) + , m_prefix{prefix} {} + ASTGEN_MEMBERS_TracePushNamePrefix; + bool same(const AstNode* samep) const override { return false; } + string prefix() const { return m_prefix; } +}; +class AstUCStmt final : public AstNodeStmt { + // User $c statement + // @astgen op1 := exprsp : List[AstNode] +public: + AstUCStmt(FileLine* fl, AstNode* exprsp) + : ASTGEN_SUPER_UCStmt(fl) { + this->addExprsp(exprsp); + } + ASTGEN_MEMBERS_UCStmt; + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } + bool isOutputter() const override { return true; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstWait final : public AstNodeStmt { + // @astgen op1 := condp : AstNode + // @astgen op2 := stmtsp : List[AstNode] +public: + AstWait(FileLine* fl, AstNode* condp, AstNode* stmtsp) + : ASTGEN_SUPER_Wait(fl) { + this->condp(condp); + this->addStmtsp(stmtsp); + } + ASTGEN_MEMBERS_Wait; + bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); } +}; +class AstWaitFork final : public AstNodeStmt { + // A "wait fork" statement +public: + explicit AstWaitFork(FileLine* fl) + : ASTGEN_SUPER_WaitFork(fl) {} + ASTGEN_MEMBERS_WaitFork; +}; +class AstWhile final : public AstNodeStmt { + // @astgen op1 := precondsp : List[AstNode] + // @astgen op2 := condp : AstNode + // @astgen op3 := stmtsp : List[AstNode] + // @astgen op4 := incsp : List[AstNode] +public: + AstWhile(FileLine* fl, AstNode* condp, AstNode* stmtsp = nullptr, AstNode* incsp = nullptr) + : ASTGEN_SUPER_While(fl) { + this->condp(condp); + this->addStmtsp(stmtsp); + this->addIncsp(incsp); + } + ASTGEN_MEMBERS_While; + bool isGateOptimizable() const override { return false; } + int instrCount() const override { return INSTR_COUNT_BRANCH; } + bool same(const AstNode* /*samep*/) const override { return true; } + // Stop statement searchback here + void addBeforeStmt(AstNode* newp, AstNode* belowp) override; + // Stop statement searchback here + void addNextStmt(AstNode* newp, AstNode* belowp) override; + bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); } +}; +class AstWith final : public AstNodeStmt { + // Used as argument to method, then to AstCMethodHard + // dtypep() contains the with lambda's return dtype + // Parents: funcref (similar to AstArg) + // Children: LambdaArgRef that declares the item variable + // Children: LambdaArgRef that declares the item.index variable + // Children: math (equation establishing the with) + // @astgen op1 := indexArgRefp : AstLambdaArgRef + // @astgen op2 := valueArgRefp : AstLambdaArgRef + // @astgen op3 := exprp : AstNode +public: + AstWith(FileLine* fl, AstLambdaArgRef* indexArgRefp, AstLambdaArgRef* valueArgRefp, + AstNode* exprp) + : ASTGEN_SUPER_With(fl) { + this->indexArgRefp(indexArgRefp); + this->valueArgRefp(valueArgRefp); + this->exprp(exprp); + } + ASTGEN_MEMBERS_With; + bool same(const AstNode* /*samep*/) const override { return true; } + bool hasDType() const override { return true; } + const char* broken() const override { + BROKEN_RTN(!indexArgRefp()); // varp needed to know lambda's arg dtype + BROKEN_RTN(!valueArgRefp()); // varp needed to know lambda's arg dtype + return nullptr; + } +}; +class AstWithParse final : public AstNodeStmt { + // In early parse, FUNC(index) WITH equation-using-index + // Replaced with AstWith + // Parents: math|stmt + // Children: funcref, math + // @astgen op1 := funcrefp : AstNode + // @astgen op2 := exprp : Optional[AstNode] +public: + AstWithParse(FileLine* fl, bool stmt, AstNode* funcrefp, AstNode* exprp) + : ASTGEN_SUPER_WithParse(fl) { + statement(stmt); + this->funcrefp(funcrefp); + this->exprp(exprp); + } + ASTGEN_MEMBERS_WithParse; + bool same(const AstNode* /*samep*/) const override { return true; } +}; + +// === AstNodeAssign === +class AstAssign final : public AstNodeAssign { +public: + AstAssign(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* timingControlp = nullptr) + : ASTGEN_SUPER_Assign(fl, lhsp, rhsp, timingControlp) { + dtypeFrom(lhsp); + } + ASTGEN_MEMBERS_Assign; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAssign(this->fileline(), lhsp, rhsp); + } + bool brokeLhsMustBeLvalue() const override { return true; } +}; +class AstAssignAlias final : public AstNodeAssign { + // Like AstAssignW, but a true bidirect interconnection alias + // If both sides are wires, there's no LHS vs RHS, +public: + AstAssignAlias(FileLine* fl, AstVarRef* lhsp, AstVarRef* rhsp) + : ASTGEN_SUPER_AssignAlias(fl, (AstNode*)lhsp, (AstNode*)rhsp) {} + ASTGEN_MEMBERS_AssignAlias; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { V3ERROR_NA_RETURN(nullptr); } + bool brokeLhsMustBeLvalue() const override { return false; } +}; +class AstAssignDly final : public AstNodeAssign { +public: + AstAssignDly(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* timingControlp = nullptr) + : ASTGEN_SUPER_AssignDly(fl, lhsp, rhsp, timingControlp) {} + ASTGEN_MEMBERS_AssignDly; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAssignDly(this->fileline(), lhsp, rhsp); + } + bool isGateOptimizable() const override { return false; } + string verilogKwd() const override { return "<="; } + bool brokeLhsMustBeLvalue() const override { return true; } +}; +class AstAssignForce final : public AstNodeAssign { + // Procedural 'force' statement +public: + AstAssignForce(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_AssignForce(fl, lhsp, rhsp) {} + ASTGEN_MEMBERS_AssignForce; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAssignForce{this->fileline(), lhsp, rhsp}; + } + bool brokeLhsMustBeLvalue() const override { return true; } +}; +class AstAssignPost final : public AstNodeAssign { + // Like Assign, but predelayed assignment requiring special order handling +public: + AstAssignPost(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_AssignPost(fl, lhsp, rhsp) {} + ASTGEN_MEMBERS_AssignPost; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAssignPost(this->fileline(), lhsp, rhsp); + } + bool brokeLhsMustBeLvalue() const override { return true; } +}; +class AstAssignPre final : public AstNodeAssign { + // Like Assign, but predelayed assignment requiring special order handling +public: + AstAssignPre(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_AssignPre(fl, lhsp, rhsp) {} + ASTGEN_MEMBERS_AssignPre; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAssignPre(this->fileline(), lhsp, rhsp); + } + bool brokeLhsMustBeLvalue() const override { return true; } +}; +class AstAssignVarScope final : public AstNodeAssign { + // Assign two VarScopes to each other +public: + AstAssignVarScope(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_AssignVarScope(fl, lhsp, rhsp) { + dtypeFrom(rhsp); + } + ASTGEN_MEMBERS_AssignVarScope; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAssignVarScope(this->fileline(), lhsp, rhsp); + } + bool brokeLhsMustBeLvalue() const override { return false; } +}; +class AstAssignW final : public AstNodeAssign { + // Like assign, but wire/assign's in verilog, the only setting of the specified variable + // @astgen op4 := strengthSpecp : Optional[AstStrengthSpec] +public: + AstAssignW(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER_AssignW(fl, lhsp, rhsp) {} + ASTGEN_MEMBERS_AssignW; + AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { + return new AstAssignW(this->fileline(), lhsp, rhsp); + } + bool brokeLhsMustBeLvalue() const override { return true; } + AstAlways* convertToAlways() { + AstNode* const lhs1p = lhsp()->unlinkFrBack(); + AstNode* const rhs1p = rhsp()->unlinkFrBack(); + AstAlways* const newp = new AstAlways(fileline(), VAlwaysKwd::ALWAYS, nullptr, + new AstAssign(fileline(), lhs1p, rhs1p)); + replaceWith(newp); // User expected to then deleteTree(); + return newp; + } +}; + +// === AstNodeCCall === +class AstCCall final : public AstNodeCCall { + // C++ function call + // Parents: Anything above a statement + // Children: Args to the function + + string m_selfPointer; // Output code object pointer (e.g.: 'this') + +public: + AstCCall(FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) + : ASTGEN_SUPER_CCall(fl, funcp, argsp) {} + ASTGEN_MEMBERS_CCall; + + string selfPointer() const { return m_selfPointer; } + void selfPointer(const string& value) { m_selfPointer = value; } + string selfPointerProtect(bool useSelfForThis) const; +}; +class AstCMethodCall final : public AstNodeCCall { + // C++ method call + // Parents: Anything above a statement + // @astgen op1 := fromp : AstNode +public: + AstCMethodCall(FileLine* fl, AstNode* fromp, AstCFunc* funcp, AstNode* argsp = nullptr) + : ASTGEN_SUPER_CMethodCall(fl, funcp, argsp) { + this->fromp(fromp); + } + ASTGEN_MEMBERS_CMethodCall; + const char* broken() const override { + BROKEN_BASE_RTN(AstNodeCCall::broken()); + BROKEN_RTN(!fromp()); + return nullptr; + } +}; +class AstCNew final : public AstNodeCCall { + // C++ new() call + // Parents: Anything above an expression + // Children: Args to the function +public: + AstCNew(FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) + : ASTGEN_SUPER_CNew(fl, funcp, argsp) { + statement(false); + } + bool hasDType() const override { return true; } + ASTGEN_MEMBERS_CNew; +}; + +// === AstNodeCase === +class AstCase final : public AstNodeCase { + // Case statement + // Parents: {statement list} +private: + VCaseType m_casex; // 0=case, 1=casex, 2=casez + bool m_fullPragma = false; // Synthesis full_case + bool m_parallelPragma = false; // Synthesis parallel_case + bool m_uniquePragma = false; // unique case + bool m_unique0Pragma = false; // unique0 case + bool m_priorityPragma = false; // priority case +public: + AstCase(FileLine* fl, VCaseType casex, AstNode* exprp, AstCaseItem* itemsp) + : ASTGEN_SUPER_Case(fl, exprp, itemsp) + , m_casex{casex} {} + ASTGEN_MEMBERS_Case; + string verilogKwd() const override { return casez() ? "casez" : casex() ? "casex" : "case"; } + bool same(const AstNode* samep) const override { + return m_casex == static_cast(samep)->m_casex; + } + bool casex() const { return m_casex == VCaseType::CT_CASEX; } + bool casez() const { return m_casex == VCaseType::CT_CASEZ; } + bool caseInside() const { return m_casex == VCaseType::CT_CASEINSIDE; } + bool caseSimple() const { return m_casex == VCaseType::CT_CASE; } + void caseInsideSet() { m_casex = VCaseType::CT_CASEINSIDE; } + bool fullPragma() const { return m_fullPragma; } + void fullPragma(bool flag) { m_fullPragma = flag; } + bool parallelPragma() const { return m_parallelPragma; } + void parallelPragma(bool flag) { m_parallelPragma = flag; } + bool uniquePragma() const { return m_uniquePragma; } + void uniquePragma(bool flag) { m_uniquePragma = flag; } + bool unique0Pragma() const { return m_unique0Pragma; } + void unique0Pragma(bool flag) { m_unique0Pragma = flag; } + bool priorityPragma() const { return m_priorityPragma; } + void priorityPragma(bool flag) { m_priorityPragma = flag; } +}; +class AstGenCase final : public AstNodeCase { + // Generate Case statement + // Parents: {statement list} +public: + AstGenCase(FileLine* fl, AstNode* exprp, AstCaseItem* itemsp) + : ASTGEN_SUPER_GenCase(fl, exprp, itemsp) {} + ASTGEN_MEMBERS_GenCase; +}; + +// === AstNodeCoverOrAssert === +class AstAssert final : public AstNodeCoverOrAssert { + // @astgen op3 := failsp: List[AstNode] // Statments when propp is failing/falsey +public: + ASTGEN_MEMBERS_Assert; + AstAssert(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp, bool immediate, + const string& name = "") + : ASTGEN_SUPER_Assert(fl, propp, passsp, immediate, name) { + this->addFailsp(failsp); + } +}; +class AstAssertIntrinsic final : public AstNodeCoverOrAssert { + // A $cast or other compiler inserted assert, that must run even without --assert option + // @astgen op3 := failsp: List[AstNode] // Statments when propp is failing/falsey +public: + ASTGEN_MEMBERS_AssertIntrinsic; + AstAssertIntrinsic(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp, + bool immediate, const string& name = "") + : ASTGEN_SUPER_AssertIntrinsic(fl, propp, passsp, immediate, name) { + this->addFailsp(failsp); + } +}; +class AstCover final : public AstNodeCoverOrAssert { + // @astgen op3 := coverincsp: List[AstNode] // Coverage node +public: + ASTGEN_MEMBERS_Cover; + AstCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, bool immediate, + const string& name = "") + : ASTGEN_SUPER_Cover(fl, propp, stmtsp, immediate, name) {} + virtual bool immediate() const { return false; } +}; +class AstRestrict final : public AstNodeCoverOrAssert { +public: + ASTGEN_MEMBERS_Restrict; + AstRestrict(FileLine* fl, AstNode* propp) + : ASTGEN_SUPER_Restrict(fl, propp, nullptr, false, "") {} +}; + +// === AstNodeFTaskRef === +class AstFuncRef final : public AstNodeFTaskRef { + // A reference to a function +public: + AstFuncRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp) + : ASTGEN_SUPER_FuncRef(fl, false, namep, pinsp) {} + AstFuncRef(FileLine* fl, const string& name, AstNode* pinsp) + : ASTGEN_SUPER_FuncRef(fl, false, name, pinsp) {} + ASTGEN_MEMBERS_FuncRef; + bool hasDType() const override { return true; } +}; +class AstMethodCall final : public AstNodeFTaskRef { + // A reference to a member task (or function) + // PARENTS: stmt/math + // Not all calls are statments vs math. AstNodeStmt needs isStatement() to deal. + // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it + // @astgen op2 := fromp : AstNode + // +public: + AstMethodCall(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name, + AstNode* pinsp) + : ASTGEN_SUPER_MethodCall(fl, false, name, pinsp) { + this->fromp(fromp); + dtypep(nullptr); // V3Width will resolve + } + AstMethodCall(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp) + : ASTGEN_SUPER_MethodCall(fl, false, name, pinsp) { + this->fromp(fromp); + } + ASTGEN_MEMBERS_MethodCall; + const char* broken() const override { + BROKEN_BASE_RTN(AstNodeFTaskRef::broken()); + BROKEN_RTN(!fromp()); + return nullptr; + } + void dump(std::ostream& str) const override; + bool hasDType() const override { return true; } + void makeStatement() { + statement(true); + dtypeSetVoid(); + } +}; +class AstNew final : public AstNodeFTaskRef { + // New as constructor + // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it + // Parents: math|stmt + // Children: varref|arraysel, math +public: + AstNew(FileLine* fl, AstNode* pinsp) + : ASTGEN_SUPER_New(fl, false, "new", pinsp) {} + ASTGEN_MEMBERS_New; + virtual bool cleanOut() const { return true; } + bool same(const AstNode* /*samep*/) const override { return true; } + bool hasDType() const override { return true; } + int instrCount() const override { return widthInstrs(); } +}; +class AstTaskRef final : public AstNodeFTaskRef { + // A reference to a task +public: + AstTaskRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp) + : ASTGEN_SUPER_TaskRef(fl, true, namep, pinsp) { + statement(true); + } + AstTaskRef(FileLine* fl, const string& name, AstNode* pinsp) + : ASTGEN_SUPER_TaskRef(fl, true, name, pinsp) {} + ASTGEN_MEMBERS_TaskRef; +}; + +// === AstNodeFor === +class AstGenFor final : public AstNodeFor { +public: + AstGenFor(FileLine* fl, AstNode* initsp, AstNode* condp, AstNode* incsp, AstNode* stmtsp) + : ASTGEN_SUPER_GenFor(fl, initsp, condp, incsp, stmtsp) {} + ASTGEN_MEMBERS_GenFor; +}; + +// === AstNodeIf === +class AstGenIf final : public AstNodeIf { +public: + AstGenIf(FileLine* fl, AstNode* condp, AstNode* thensp, AstNode* elsesp) + : ASTGEN_SUPER_GenIf(fl, condp, thensp, elsesp) {} + ASTGEN_MEMBERS_GenIf; +}; +class AstIf final : public AstNodeIf { +private: + bool m_uniquePragma = false; // unique case + bool m_unique0Pragma = false; // unique0 case + bool m_priorityPragma = false; // priority case +public: + AstIf(FileLine* fl, AstNode* condp, AstNode* thensp = nullptr, AstNode* elsesp = nullptr) + : ASTGEN_SUPER_If(fl, condp, thensp, elsesp) {} + ASTGEN_MEMBERS_If; + bool uniquePragma() const { return m_uniquePragma; } + void uniquePragma(bool flag) { m_uniquePragma = flag; } + bool unique0Pragma() const { return m_unique0Pragma; } + void unique0Pragma(bool flag) { m_unique0Pragma = flag; } + bool priorityPragma() const { return m_priorityPragma; } + void priorityPragma(bool flag) { m_priorityPragma = flag; } +}; + +// === AstNodeReadWriteMem === +class AstReadMem final : public AstNodeReadWriteMem { +public: + AstReadMem(FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, AstNode* lsbp, + AstNode* msbp) + : ASTGEN_SUPER_ReadMem(fl, hex, filenamep, memp, lsbp, msbp) {} + ASTGEN_MEMBERS_ReadMem; + string verilogKwd() const override { return (isHex() ? "$readmemh" : "$readmemb"); } + const char* cFuncPrefixp() const override { return "VL_READMEM_"; } +}; +class AstWriteMem final : public AstNodeReadWriteMem { +public: + AstWriteMem(FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, AstNode* lsbp, + AstNode* msbp) + : ASTGEN_SUPER_WriteMem(fl, hex, filenamep, memp, lsbp, msbp) {} + ASTGEN_MEMBERS_WriteMem; + string verilogKwd() const override { return (isHex() ? "$writememh" : "$writememb"); } + const char* cFuncPrefixp() const override { return "VL_WRITEMEM_"; } +}; + +// === AstNodeText === +class AstScCtor final : public AstNodeText { +public: + AstScCtor(FileLine* fl, const string& textp) + : ASTGEN_SUPER_ScCtor(fl, textp) {} + ASTGEN_MEMBERS_ScCtor; + bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs + bool isOutputter() const override { return true; } +}; +class AstScDtor final : public AstNodeText { +public: + AstScDtor(FileLine* fl, const string& textp) + : ASTGEN_SUPER_ScDtor(fl, textp) {} + ASTGEN_MEMBERS_ScDtor; + bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs + bool isOutputter() const override { return true; } +}; +class AstScHdr final : public AstNodeText { +public: + AstScHdr(FileLine* fl, const string& textp) + : ASTGEN_SUPER_ScHdr(fl, textp) {} + ASTGEN_MEMBERS_ScHdr; + bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs + bool isOutputter() const override { return true; } +}; +class AstScImp final : public AstNodeText { +public: + AstScImp(FileLine* fl, const string& textp) + : ASTGEN_SUPER_ScImp(fl, textp) {} + ASTGEN_MEMBERS_ScImp; + bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs + bool isOutputter() const override { return true; } +}; +class AstScImpHdr final : public AstNodeText { +public: + AstScImpHdr(FileLine* fl, const string& textp) + : ASTGEN_SUPER_ScImpHdr(fl, textp) {} + ASTGEN_MEMBERS_ScImpHdr; + bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs + bool isOutputter() const override { return true; } +}; +class AstScInt final : public AstNodeText { +public: + AstScInt(FileLine* fl, const string& textp) + : ASTGEN_SUPER_ScInt(fl, textp) {} + ASTGEN_MEMBERS_ScInt; + bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs + bool isOutputter() const override { return true; } +}; + +// === AstNodeSimpleText === +class AstText final : public AstNodeSimpleText { +public: + AstText(FileLine* fl, const string& textp, bool tracking = false) + : ASTGEN_SUPER_Text(fl, textp, tracking) {} + ASTGEN_MEMBERS_Text; +}; +class AstTextBlock final : public AstNodeSimpleText { + // @astgen op1 := nodesp : List[AstNode] + bool m_commas; // Comma separate emitted children +public: + explicit AstTextBlock(FileLine* fl, const string& textp = "", bool tracking = false, + bool commas = false) + : ASTGEN_SUPER_TextBlock(fl, textp, tracking) + , m_commas(commas) {} + ASTGEN_MEMBERS_TextBlock; + void commas(bool flag) { m_commas = flag; } + bool commas() const { return m_commas; } + void addText(FileLine* fl, const string& textp, bool tracking = false) { + addNodesp(new AstText(fl, textp, tracking)); + } +}; + +#endif // Guard diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index f8a409247..af7f7d74c 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -26,7 +26,7 @@ #include "V3PartitionGraph.h" // Just for mtask dumping #include "V3String.h" -#include "V3AstNodes__gen_macros.h" // Generated by 'astgen' +#include "V3Ast__gen_macros.h" // Generated by 'astgen' #include #include @@ -155,6 +155,51 @@ void AstNodeCond::numberOperate(V3Number& out, const V3Number& lhs, const V3Numb } } +void AstBasicDType::init(VBasicDTypeKwd kwd, VSigning numer, int wantwidth, int wantwidthmin, + AstRange* rangep) { + // wantwidth=0 means figure it out, but if a widthmin is >=0 + // we allow width 0 so that {{0{x}},y} works properly + // wantwidthmin=-1: default, use wantwidth if it is non zero + m.m_keyword = kwd; + // Implicitness: // "parameter X" is implicit and sized from initial + // value, "parameter reg x" not + if (keyword() == VBasicDTypeKwd::LOGIC_IMPLICIT) { + if (rangep || wantwidth) m.m_keyword = VBasicDTypeKwd::LOGIC; + } + if (numer == VSigning::NOSIGN) { + if (keyword().isSigned()) { + numer = VSigning::SIGNED; + } else if (keyword().isUnsigned()) { + numer = VSigning::UNSIGNED; + } + } + numeric(numer); + if (!rangep && (wantwidth || wantwidthmin >= 0)) { // Constant width + if (wantwidth > 1) m.m_nrange.init(wantwidth - 1, 0, false); + const int wmin = wantwidthmin >= 0 ? wantwidthmin : wantwidth; + widthForce(wantwidth, wmin); + } else if (!rangep) { // Set based on keyword properties + // V3Width will pull from this width + if (keyword().width() > 1 && !isOpaque()) { + m.m_nrange.init(keyword().width() - 1, 0, false); + } + widthForce(keyword().width(), keyword().width()); + } else { + widthForce(rangep->elementsConst(), + rangep->elementsConst()); // Maybe unknown if parameters underneath it + } + this->rangep(rangep); + this->dtypep(this); +} + +void AstBasicDType::cvtRangeConst() { + if (rangep() && VN_IS(rangep()->leftp(), Const) && VN_IS(rangep()->rightp(), Const)) { + m.m_nrange = VNumRange{rangep()->leftConst(), rangep()->rightConst()}; + rangep()->unlinkFrBackWithNext()->deleteTree(); + rangep(nullptr); + } +} + int AstBasicDType::widthAlignBytes() const { if (width() <= 8) { return 1; @@ -519,11 +564,11 @@ string AstVar::dpiArgType(bool named, bool forReturn) const { return dpiTypesToStringConverter{}.convert(this); } else { class converter final : public dpiTypesToStringConverter { - virtual string bitLogicVector(const AstVar* varp, bool isBit) const override { + string bitLogicVector(const AstVar* varp, bool isBit) const override { return string(varp->isReadOnly() ? "const " : "") + dpiTypesToStringConverter::bitLogicVector(varp, isBit) + '*'; } - virtual string primitive(const AstVar* varp) const override { + string primitive(const AstVar* varp) const override { string type = dpiTypesToStringConverter::primitive(varp); if (varp->isWritable() || VN_IS(varp->dtypep()->skipRefp(), UnpackArrayDType)) { if (!varp->isWritable() && varp->basicp()->keyword() != VBasicDTypeKwd::STRING) @@ -555,16 +600,16 @@ string AstVar::dpiTmpVarType(const string& varName) const { return ""; } } - virtual string openArray(const AstVar* varp) const override { + string openArray(const AstVar* varp) const override { return dpiTypesToStringConverter::openArray(varp) + ' ' + m_name + arraySuffix(varp, 0); } - virtual string bitLogicVector(const AstVar* varp, bool isBit) const override { + string bitLogicVector(const AstVar* varp, bool isBit) const override { string type = dpiTypesToStringConverter::bitLogicVector(varp, isBit); type += ' ' + m_name + arraySuffix(varp, varp->widthWords()); return type; } - virtual string primitive(const AstVar* varp) const override { + string primitive(const AstVar* varp) const override { string type = dpiTypesToStringConverter::primitive(varp); if (varp->isWritable() || VN_IS(varp->dtypep()->skipRefp(), UnpackArrayDType)) { if (!varp->isWritable() && varp->basicp()->keyword() == VBasicDTypeKwd::CHANDLE) @@ -615,29 +660,21 @@ AstVar* AstVar::scVarRecurse(AstNode* nodep) { } else { return nullptr; } - } else if (VN_IS(nodep, VarRef)) { - if (VN_AS(nodep, VarRef)->varp()->isSc()) { - return VN_AS(nodep, VarRef)->varp(); + } else if (AstVarRef* const vrefp = VN_CAST(nodep, VarRef)) { + if (vrefp->varp()->isSc()) { + return vrefp->varp(); } else { return nullptr; } - } else if (VN_IS(nodep, ArraySel)) { - if (nodep->op1p()) { - if (AstVar* p = scVarRecurse(nodep->op1p())) return p; - } - if (nodep->op2p()) { - if (AstVar* p = scVarRecurse(nodep->op2p())) return p; - } - if (nodep->op3p()) { - if (AstVar* p = scVarRecurse(nodep->op3p())) return p; - } - if (nodep->op4p()) { - if (AstVar* p = scVarRecurse(nodep->op4p())) return p; - } + } else if (AstArraySel* const arraySelp = VN_CAST(nodep, ArraySel)) { + if (AstVar* const p = scVarRecurse(arraySelp->fromp())) return p; + if (AstVar* const p = scVarRecurse(arraySelp->bitp())) return p; } return nullptr; } +bool AstNodeDType::isFourstate() const { return basicp()->isFourstate(); } + class AstNodeDType::CTypeRecursed final { public: string m_type; // The base type, e.g.: "Foo_t"s @@ -1023,8 +1060,13 @@ AstConstPool::AstConstPool(FileLine* fl) : ASTGEN_SUPER_ConstPool(fl) , m_modp{new AstModule(fl, "@CONST-POOL@")} , m_scopep{new AstScope(fl, m_modp, "@CONST-POOL@", nullptr, nullptr)} { - addOp1p(m_modp); - m_modp->addStmtp(m_scopep); + this->modulep(m_modp); + m_modp->addStmtsp(m_scopep); +} +const char* AstConstPool::broken() const { + BROKEN_RTN(m_modp && !m_modp->brokeExists()); + BROKEN_RTN(m_scopep && !m_scopep->brokeExists()); + return nullptr; } AstVarScope* AstConstPool::createNewEntry(const string& name, AstNode* initp) { @@ -1033,9 +1075,9 @@ AstVarScope* AstConstPool::createNewEntry(const string& name, AstNode* initp) { varp->isConst(true); varp->isStatic(true); varp->valuep(initp->cloneTree(false)); - m_modp->addStmtp(varp); + m_modp->addStmtsp(varp); AstVarScope* const varScopep = new AstVarScope(fl, m_scopep, varp); - m_scopep->addVarp(varScopep); + m_scopep->addVarsp(varScopep); return varScopep; } @@ -1181,7 +1223,7 @@ void AstWhile::addBeforeStmt(AstNode* newp, AstNode* belowp) { } else if (belowp == condp()) { // Goes before condition, IE in preconditions addPrecondsp(newp); - } else if (belowp == bodysp()) { + } else if (belowp == stmtsp()) { // Was first statement in body, so new front belowp->addHereThisAsNext(newp); } else { @@ -1198,12 +1240,12 @@ void AstWhile::addNextStmt(AstNode* newp, AstNode* belowp) { belowp->addNextHere(newp); } else if (belowp == condp()) { // Becomes first statement in body, body may have been empty - if (bodysp()) { - bodysp()->addHereThisAsNext(newp); + if (stmtsp()) { + stmtsp()->addHereThisAsNext(newp); } else { - addBodysp(newp); + addStmtsp(newp); } - } else if (belowp == bodysp()) { + } else if (belowp == stmtsp()) { // Next statement in body belowp->addNextHere(newp); } else { @@ -1224,10 +1266,10 @@ static std::string nodeAddr(const AstNode* nodep) { } void AstNode::dump(std::ostream& str) const { - str << typeName() << " " - << nodeAddr(this) - //<< " " << nodeAddr(m_backp) + str << typeName() << " " << nodeAddr(this) +#ifdef VL_DEBUG << " = editCountLast()) ? "#>" : ">") +#endif << " {" << fileline()->filenameLetters() << std::dec << fileline()->lastLineno() << fileline()->firstColumnLetters() << "}"; if (user1p()) str << " u1=" << nodeAddr(user1p()); @@ -1297,11 +1339,19 @@ void AstCell::dump(std::ostream& str) const { str << " ->UNLINKED:" << modName(); } } +const char* AstCell::broken() const { + BROKEN_RTN(m_modp && !m_modp->brokeExists()); + return nullptr; +} void AstCellInline::dump(std::ostream& str) const { this->AstNode::dump(str); str << " -> " << origModName(); str << " [scopep=" << reinterpret_cast(scopep()) << "]"; } +const char* AstCellInline::broken() const { + BROKEN_RTN(m_scopep && !m_scopep->brokeExists()); + return nullptr; +} const char* AstClassPackage::broken() const { BROKEN_BASE_RTN(AstNodeModule::broken()); BROKEN_RTN(m_classp && !m_classp->brokeExists()); @@ -1346,6 +1396,17 @@ void AstClass::dump(std::ostream& str) const { if (isExtended()) str << " [EXT]"; if (isVirtual()) str << " [VIRT]"; } +const char* AstClass::broken() const { + BROKEN_BASE_RTN(AstNodeModule::broken()); + BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); + return nullptr; +} +void AstClass::cloneRelink() { + AstNodeModule::cloneRelink(); + if (m_classOrPackagep && m_classOrPackagep->clonep()) { + m_classOrPackagep = m_classOrPackagep->clonep(); + } +} AstClass* AstClassExtends::classp() const { const AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType); if (VL_UNLIKELY(!refp)) { // LinkDot uses this for 'super.' @@ -1368,6 +1429,18 @@ void AstClassRefDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); str << "class:" << name(); } +const char* AstClassRefDType::broken() const { + BROKEN_RTN(m_classp && !m_classp->brokeExists()); + BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); + return nullptr; +} +void AstClassRefDType::cloneRelink() { + if (m_classp && m_classp->clonep()) m_classp = m_classp->clonep(); + if (m_classOrPackagep && m_classOrPackagep->clonep()) { + m_classOrPackagep = m_classOrPackagep->clonep(); + } +} +string AstClassRefDType::name() const { return classp() ? classp()->name() : ""; } void AstNodeCoverOrAssert::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); if (immediate()) str << " [IMMEDIATE]"; @@ -1385,6 +1458,11 @@ void AstEnumItemRef::dump(std::ostream& str) const { str << "UNLINKED"; } } +const char* AstEnumItemRef::broken() const { + BROKEN_RTN(m_itemp && !m_itemp->brokeExists()); + BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); + return nullptr; +} void AstIfaceRefDType::dump(std::ostream& str) const { this->AstNodeDType::dump(str); if (cellName() != "") str << " cell=" << cellName(); @@ -1404,6 +1482,11 @@ void AstIfaceRefDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); str << "iface"; } +void AstIfaceRefDType::cloneRelink() { + if (m_cellp && m_cellp->clonep()) m_cellp = m_cellp->clonep(); + if (m_ifacep && m_ifacep->clonep()) m_ifacep = m_ifacep->clonep(); + if (m_modportp && m_modportp->clonep()) m_modportp = m_modportp->clonep(); +} void AstInitArray::dump(std::ostream& str) const { this->AstNode::dump(str); int n = 0; @@ -1416,6 +1499,42 @@ void AstInitArray::dump(std::ostream& str) const { str << " [" << itr.first << "]=" << reinterpret_cast(itr.second); } } +const char* AstInitArray::broken() const { + for (KeyItemMap::const_iterator it = m_map.begin(); it != m_map.end(); ++it) { + BROKEN_RTN(!it->second); + BROKEN_RTN(!it->second->brokeExists()); + } + return nullptr; +} +void AstInitArray::cloneRelink() { + for (KeyItemMap::iterator it = m_map.begin(); it != m_map.end(); ++it) { + if (it->second->clonep()) it->second = it->second->clonep(); + } +} +void AstInitArray::addIndexValuep(uint64_t index, AstNode* newp) { + const auto it = m_map.find(index); + if (it != m_map.end()) { + it->second->valuep(newp); + } else { + AstInitItem* const itemp = new AstInitItem(fileline(), newp); + m_map.emplace(index, itemp); + addInitsp(itemp); + } +} +AstNode* AstInitArray::getIndexValuep(uint64_t index) const { + const auto it = m_map.find(index); + if (it == m_map.end()) { + return nullptr; + } else { + return it->second->valuep(); + } +} +AstNode* AstInitArray::getIndexDefaultedValuep(uint64_t index) const { + AstNode* valuep = getIndexValuep(index); + if (!valuep) valuep = defaultp(); + return valuep; +} + void AstJumpGo::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); str << " -> "; @@ -1425,6 +1544,13 @@ void AstJumpGo::dump(std::ostream& str) const { str << "%Error:UNLINKED"; } } +const char* AstJumpGo::broken() const { + BROKEN_RTN(!labelp()->brokeExistsBelow()); + return nullptr; +} +void AstJumpGo::cloneRelink() { + if (m_labelp->clonep()) m_labelp = m_labelp->clonep(); +} void AstJumpLabel::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); str << " -> "; @@ -1447,6 +1573,13 @@ void AstMemberSel::dump(std::ostream& str) const { str << "%Error:UNLINKED"; } } +void AstMemberSel::cloneRelink() { + if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep(); +} +const char* AstMemberSel::broken() const { + BROKEN_RTN(m_varp && !m_varp->brokeExists()); + return nullptr; +} void AstMethodCall::dump(std::ostream& str) const { this->AstNodeFTaskRef::dump(str); if (isStatement()) str << " [STMT]"; @@ -1468,6 +1601,13 @@ void AstModportFTaskRef::dump(std::ostream& str) const { str << " -> UNLINKED"; } } +const char* AstModportFTaskRef::broken() const { + BROKEN_RTN(m_ftaskp && !m_ftaskp->brokeExists()); + return nullptr; +} +void AstModportFTaskRef::cloneRelink() { + if (m_ftaskp && m_ftaskp->clonep()) m_ftaskp = m_ftaskp->clonep(); +} void AstModportVarRef::dump(std::ostream& str) const { this->AstNode::dump(str); if (direction().isAny()) str << " " << direction(); @@ -1478,6 +1618,13 @@ void AstModportVarRef::dump(std::ostream& str) const { str << " -> UNLINKED"; } } +const char* AstModportVarRef::broken() const { + BROKEN_RTN(m_varp && !m_varp->brokeExists()); + return nullptr; +} +void AstModportVarRef::cloneRelink() { + if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep(); +} void AstPin::dump(std::ostream& str) const { this->AstNode::dump(str); if (modVarp()) { @@ -1488,6 +1635,17 @@ void AstPin::dump(std::ostream& str) const { } if (svImplicit()) str << " [.SV]"; } +const char* AstPin::broken() const { + BROKEN_RTN(m_modVarp && !m_modVarp->brokeExists()); + BROKEN_RTN(m_modPTypep && !m_modPTypep->brokeExists()); + return nullptr; +} +string AstPin::prettyOperatorName() const { + return modVarp() + ? ((modVarp()->direction().isAny() ? modVarp()->direction().prettyName() + " " : "") + + "port connection " + modVarp()->prettyNameQ()) + : "port connection"; +} void AstPrintTimeScale::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); str << " " << timeunit(); @@ -1533,6 +1691,23 @@ void AstRefDType::dump(std::ostream& str) const { str << " -> UNLINKED"; } } +const char* AstRefDType::broken() const { + BROKEN_RTN(m_typedefp && !m_typedefp->brokeExists()); + BROKEN_RTN(m_refDTypep && !m_refDTypep->brokeExists()); + BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); + return nullptr; +} +void AstRefDType::cloneRelink() { + if (m_typedefp && m_typedefp->clonep()) m_typedefp = m_typedefp->clonep(); + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); + if (m_classOrPackagep && m_classOrPackagep->clonep()) { + m_classOrPackagep = m_classOrPackagep->clonep(); + } +} +AstNodeDType* AstRefDType::subDTypep() const { + if (typedefp()) return typedefp()->subDTypep(); + return refDTypep(); // Maybe nullptr +} void AstNodeUOrStructDType::dump(std::ostream& str) const { this->AstNodeDType::dump(str); if (packed()) str << " [PACKED]"; @@ -1603,6 +1778,32 @@ void AstNetlist::dump(std::ostream& str) const { this->AstNode::dump(str); str << " [" << timeunit() << "/" << timeprecision() << "]"; } +const char* AstNetlist::broken() const { + BROKEN_RTN(m_typeTablep && !m_typeTablep->brokeExists()); + BROKEN_RTN(m_constPoolp && !m_constPoolp->brokeExists()); + BROKEN_RTN(m_dollarUnitPkgp && !m_dollarUnitPkgp->brokeExists()); + BROKEN_RTN(m_evalp && !m_evalp->brokeExists()); + BROKEN_RTN(m_dpiExportTriggerp && !m_dpiExportTriggerp->brokeExists()); + BROKEN_RTN(m_topScopep && !m_topScopep->brokeExists()); + return nullptr; +} +AstPackage* AstNetlist::dollarUnitPkgAddp() { + if (!m_dollarUnitPkgp) { + m_dollarUnitPkgp = new AstPackage(fileline(), AstPackage::dollarUnitName()); + // packages are always libraries; don't want to make them a "top" + m_dollarUnitPkgp->inLibrary(true); + m_dollarUnitPkgp->modTrace(false); // may reconsider later + m_dollarUnitPkgp->internal(true); + addModulesp(m_dollarUnitPkgp); + } + return m_dollarUnitPkgp; +} +void AstNetlist::createTopScope(AstScope* scopep) { + UASSERT(scopep, "Must not be nullptr"); + UASSERT_OBJ(!m_topScopep, scopep, "TopScope already exits"); + m_topScopep = new AstTopScope{scopep->modp()->fileline(), scopep}; + scopep->modp()->addStmtsp(v3Global.rootp()->topScopep()); +} void AstNodeModule::dump(std::ostream& str) const { this->AstNode::dump(str); str << " L" << level(); @@ -1620,10 +1821,24 @@ void AstPackageExport::dump(std::ostream& str) const { this->AstNode::dump(str); str << " -> " << packagep(); } +const char* AstPackageExport ::broken() const { + BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); + return nullptr; +} +void AstPackageExport::cloneRelink() { + if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep(); +} void AstPackageImport::dump(std::ostream& str) const { this->AstNode::dump(str); str << " -> " << packagep(); } +const char* AstPackageImport::broken() const { + BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); + return nullptr; +} +void AstPackageImport::cloneRelink() { + if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep(); +} void AstPatMember::dump(std::ostream& str) const { this->AstNodeMath::dump(str); if (isDefault()) str << " [DEFAULT]"; @@ -1650,7 +1865,7 @@ void AstTypeTable::dump(std::ostream& str) const { for (int i = 0; i < static_cast(VBasicDTypeKwd::_ENUM_MAX); ++i) { if (AstBasicDType* const subnodep = m_basicps[i]) { str << '\n'; // Newline from caller, so newline first - str << "\t\t" << std::setw(8) << VBasicDTypeKwd(i).ascii(); + str << "\t\t" << std::setw(8) << VBasicDTypeKwd{i}.ascii(); str << " -> "; subnodep->dump(str); } @@ -1691,10 +1906,30 @@ void AstWildcardArrayDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); str << "[*]"; } +bool AstWildcardArrayDType::same(const AstNode* samep) const { + const AstNodeArrayDType* const asamep = static_cast(samep); + if (!asamep->subDTypep()) return false; + return (subDTypep() == asamep->subDTypep()); +} +bool AstWildcardArrayDType::similarDType(AstNodeDType* samep) const { + const AstNodeArrayDType* const asamep = static_cast(samep); + return type() == samep->type() && asamep->subDTypep() + && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); +} void AstUnsizedArrayDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); str << "[]"; } +bool AstUnsizedArrayDType::same(const AstNode* samep) const { + const AstNodeArrayDType* const asamep = static_cast(samep); + if (!asamep->subDTypep()) return false; + return (subDTypep() == asamep->subDTypep()); +} +bool AstUnsizedArrayDType::similarDType(AstNodeDType* samep) const { + const AstNodeArrayDType* const asamep = static_cast(samep); + return type() == samep->type() && asamep->subDTypep() + && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); +} void AstEmptyQueueDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); str << "emptyq"; @@ -1742,6 +1977,9 @@ void AstVarRef::dump(std::ostream& str) const { str << "UNLINKED"; } } +bool AstVarRef::same(const AstNode* samep) const { + return same(static_cast(samep)); +} void AstVar::dump(std::ostream& str) const { this->AstNode::dump(str); if (isSc()) str << " [SC]"; @@ -1786,6 +2024,10 @@ void AstSenItem::dump(std::ostream& str) const { this->AstNode::dump(str); str << " [" << edgeType().ascii() << "]"; } +void AstStrengthSpec::dump(std::ostream& str) const { + this->AstNode::dump(str); + str << " (" << m_s0.ascii() << ", " << m_s1.ascii() << ")"; +} void AstParseRef::dump(std::ostream& str) const { this->AstNode::dump(str); str << " [" << expect().ascii() << "]"; @@ -1800,6 +2042,13 @@ void AstClassOrPackageRef::dump(std::ostream& str) const { str << "UNLINKED"; } } +AstNodeModule* AstClassOrPackageRef::classOrPackagep() const { + AstNode* foundp = m_classOrPackageNodep; + while (auto* const anodep = VN_CAST(foundp, Typedef)) foundp = anodep->subDTypep(); + if (auto* const anodep = VN_CAST(foundp, ClassRefDType)) foundp = anodep->classp(); + return VN_CAST(foundp, NodeModule); +} + void AstDot::dump(std::ostream& str) const { this->AstNode::dump(str); if (colon()) str << " [::]"; @@ -1813,6 +2062,16 @@ void AstActive::dump(std::ostream& str) const { str << "UNLINKED"; } } +const char* AstActive::broken() const { + BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists()); + return nullptr; +} +void AstActive::cloneRelink() { + if (m_sensesp->clonep()) { + m_sensesp = m_sensesp->clonep(); + UASSERT(m_sensesp, "Bad clone cross link: " << this); + } +} void AstNodeFTaskRef::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep()); @@ -1916,6 +2175,14 @@ void AstCFunc::dump(std::ostream& str) const { if (isDestructor()) str << " [DTOR]"; if (isVirtual()) str << " [VIRT]"; } +const char* AstCFunc::broken() const { + BROKEN_RTN((m_scopep && !m_scopep->brokeExists())); + return nullptr; +} +void AstCFunc::cloneRelink() { + if (m_scopep && m_scopep->clonep()) m_scopep = m_scopep->clonep(); +} + void AstCUse::dump(std::ostream& str) const { this->AstNode::dump(str); str << " [" << useType() << "]"; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h deleted file mode 100644 index 64c25e494..000000000 --- a/src/V3AstNodes.h +++ /dev/null @@ -1,9571 +0,0 @@ -// -*- mode: C++; c-file-style: "cc-mode" -*- -//************************************************************************* -// DESCRIPTION: Verilator: Ast node structure -// -// Code available from: https://verilator.org -// -//************************************************************************* -// -// Copyright 2003-2022 by Wilson Snyder. This program is free software; you -// can redistribute it and/or modify it under the terms of either the GNU -// Lesser General Public License Version 3 or the Perl Artistic License -// Version 2.0. -// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -// -//************************************************************************* - -#ifndef VERILATOR_V3ASTNODES_H_ -#define VERILATOR_V3ASTNODES_H_ - -#ifndef VERILATOR_V3AST_H_ -#error "Use V3Ast.h as the include" -#include "V3Ast.h" // This helps code analysis tools pick up symbols in V3Ast.h -#endif - -//###################################################################### -// Standard defines for all AstNode final classes - -#define ASTNODE_NODE_FUNCS_NO_DTOR(name) \ - virtual void accept(VNVisitor& v) override { v.visit(this); } \ - virtual AstNode* clone() override { return new Ast##name(*this); } \ - static Ast##name* cloneTreeNull(Ast##name* nodep, bool cloneNextLink) { \ - return nodep ? nodep->cloneTree(cloneNextLink) : nullptr; \ - } \ - Ast##name* cloneTree(bool cloneNext) { \ - return static_cast(AstNode::cloneTree(cloneNext)); \ - } \ - Ast##name* clonep() const { return static_cast(AstNode::clonep()); } - -#define ASTNODE_NODE_FUNCS(name) \ - virtual ~Ast##name() override = default; \ - ASTNODE_NODE_FUNCS_NO_DTOR(name) - -//###################################################################### -// Macros generated by 'astgen' - -#include "V3AstNodes__gen_macros.h" - -//###################################################################### -//=== Ast* : Specific types -// Netlist interconnect - -class AstConst final : public AstNodeMath { - // A constant -private: - V3Number m_num; // Constant value - void initWithNumber() { - if (m_num.isDouble()) { - dtypeSetDouble(); - } else if (m_num.isString()) { - dtypeSetString(); - } else { - dtypeSetLogicUnsized(m_num.width(), (m_num.sized() ? 0 : m_num.widthMin()), - VSigning::fromBool(m_num.isSigned())); - } - m_num.nodep(this); - } - -public: - AstConst(FileLine* fl, const V3Number& num) - : ASTGEN_SUPER_Const(fl) - , m_num(num) { - initWithNumber(); - } - class WidthedValue {}; // for creator type-overload selection - AstConst(FileLine* fl, WidthedValue, int width, uint32_t value) - : ASTGEN_SUPER_Const(fl) - , m_num(this, width, value) { - initWithNumber(); - } - class DTyped {}; // for creator type-overload selection - // Zero/empty constant with a type matching nodetypep - AstConst(FileLine* fl, DTyped, const AstNodeDType* nodedtypep) - : ASTGEN_SUPER_Const(fl) - , m_num(this, nodedtypep) { - initWithNumber(); - } - class StringToParse {}; // for creator type-overload selection - AstConst(FileLine* fl, StringToParse, const char* sourcep) - : ASTGEN_SUPER_Const(fl) - , m_num(this, sourcep) { - initWithNumber(); - } - class VerilogStringLiteral {}; // for creator type-overload selection - AstConst(FileLine* fl, VerilogStringLiteral, const string& str) - : ASTGEN_SUPER_Const(fl) - , m_num(V3Number::VerilogStringLiteral(), this, str) { - initWithNumber(); - } - AstConst(FileLine* fl, uint32_t num) - : ASTGEN_SUPER_Const(fl) - , m_num(this, 32, num) { - dtypeSetLogicUnsized(m_num.width(), 0, VSigning::UNSIGNED); - } - class Unsized32 {}; // for creator type-overload selection - AstConst(FileLine* fl, Unsized32, uint32_t num) // Unsized 32-bit integer of specified value - : ASTGEN_SUPER_Const(fl) - , m_num(this, 32, num) { - m_num.width(32, false); - dtypeSetLogicUnsized(32, m_num.widthMin(), VSigning::UNSIGNED); - } - class Signed32 {}; // for creator type-overload selection - AstConst(FileLine* fl, Signed32, int32_t num) // Signed 32-bit integer of specified value - : ASTGEN_SUPER_Const(fl) - , m_num(this, 32, num) { - m_num.width(32, true); - dtypeSetLogicUnsized(32, m_num.widthMin(), VSigning::SIGNED); - } - class Unsized64 {}; // for creator type-overload selection - AstConst(FileLine* fl, Unsized64, uint64_t num) - : ASTGEN_SUPER_Const(fl) - , m_num(this, 64, 0) { - m_num.setQuad(num); - dtypeSetLogicSized(64, VSigning::UNSIGNED); - } - class SizedEData {}; // for creator type-overload selection - AstConst(FileLine* fl, SizedEData, uint64_t num) - : ASTGEN_SUPER_Const(fl) - , m_num(this, VL_EDATASIZE, 0) { - m_num.setQuad(num); - dtypeSetLogicSized(VL_EDATASIZE, VSigning::UNSIGNED); - } - class RealDouble {}; // for creator type-overload selection - AstConst(FileLine* fl, RealDouble, double num) - : ASTGEN_SUPER_Const(fl) - , m_num(this, 64) { - m_num.setDouble(num); - dtypeSetDouble(); - } - class String {}; // for creator type-overload selection - AstConst(FileLine* fl, String, const string& num) - : ASTGEN_SUPER_Const(fl) - , m_num(V3Number::String(), this, num) { - dtypeSetString(); - } - class BitFalse {}; - AstConst(FileLine* fl, BitFalse) // Shorthand const 0, dtype should be a logic of size 1 - : ASTGEN_SUPER_Const(fl) - , m_num(this, 1, 0) { - dtypeSetBit(); - } - // Shorthand const 1 (or with argument 0/1), dtype should be a logic of size 1 - class BitTrue {}; - AstConst(FileLine* fl, BitTrue, bool on = true) - : ASTGEN_SUPER_Const(fl) - , m_num(this, 1, on) { - dtypeSetBit(); - } - class Null {}; - AstConst(FileLine* fl, Null) - : ASTGEN_SUPER_Const(fl) - , m_num(V3Number::Null{}, this) { - dtypeSetBit(); // Events 1 bit, objects 64 bits, so autoExtend=1 and use bit here - initWithNumber(); - } - ASTNODE_NODE_FUNCS(Const) - virtual string name() const override { return num().ascii(); } // * = Value - const V3Number& num() const { return m_num; } // * = Value - V3Number& num() { return m_num; } // * = Value - uint32_t toUInt() const { return num().toUInt(); } - int32_t toSInt() const { return num().toSInt(); } - uint64_t toUQuad() const { return num().toUQuad(); } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual bool same(const AstNode* samep) const override { - const AstConst* const sp = static_cast(samep); - return num().isCaseEq(sp->num()); - } - virtual int instrCount() const override { return widthInstrs(); } - bool isEqAllOnes() const { return num().isEqAllOnes(width()); } - bool isEqAllOnesV() const { return num().isEqAllOnes(widthMinV()); } - // Parse string and create appropriate type of AstConst. - // May return nullptr on parse failure. - static AstConst* parseParamLiteral(FileLine* fl, const string& literal); -}; - -class AstEmpty final : public AstNode { - // Represents something missing, e.g. a missing argument in FOREACH -public: - explicit AstEmpty(FileLine* fl) - : ASTGEN_SUPER_Empty(fl) {} - ASTNODE_NODE_FUNCS(Empty) - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstEmptyQueue final : public AstNodeMath { -public: - explicit AstEmptyQueue(FileLine* fl) - : ASTGEN_SUPER_EmptyQueue(fl) {} - ASTNODE_NODE_FUNCS(EmptyQueue) - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitVerilog() override { return "{}"; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual bool cleanOut() const override { return true; } -}; - -class AstRange final : public AstNodeRange { - // Range specification, for use under variables and cells -public: - AstRange(FileLine* fl, AstNode* leftp, AstNode* rightp) - : ASTGEN_SUPER_Range(fl) { - setOp2p(leftp); - setOp3p(rightp); - } - AstRange(FileLine* fl, int left, int right) - : ASTGEN_SUPER_Range(fl) { - setOp2p(new AstConst(fl, left)); - setOp3p(new AstConst(fl, right)); - } - AstRange(FileLine* fl, const VNumRange& range) - : ASTGEN_SUPER_Range(fl) { - setOp2p(new AstConst(fl, range.left())); - setOp3p(new AstConst(fl, range.right())); - } - ASTNODE_NODE_FUNCS(Range) - AstNode* leftp() const { return op2p(); } - AstNode* rightp() const { return op3p(); } - int leftConst() const { - AstConst* const constp = VN_CAST(leftp(), Const); - return (constp ? constp->toSInt() : 0); - } - int rightConst() const { - AstConst* const constp = VN_CAST(rightp(), Const); - return (constp ? constp->toSInt() : 0); - } - int hiConst() const { - const int l = leftConst(); - const int r = rightConst(); - return l > r ? l : r; - } - int loConst() const { - const int l = leftConst(); - const int r = rightConst(); - return l > r ? r : l; - } - int elementsConst() const { return hiConst() - loConst() + 1; } - bool littleEndian() const { return leftConst() < rightConst(); } - virtual void dump(std::ostream& str) const override; - virtual string emitC() { V3ERROR_NA_RETURN(""); } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstBracketRange final : public AstNodeRange { - // Parser only concept "[lhsp]", a AstUnknownRange, QueueRange or Range, - // unknown until lhsp type is determined -public: - AstBracketRange(FileLine* fl, AstNode* elementsp) - : ASTGEN_SUPER_BracketRange(fl) { - setOp1p(elementsp); - } - ASTNODE_NODE_FUNCS(BracketRange) - virtual string emitC() { V3ERROR_NA_RETURN(""); } - virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - // Will be removed in V3Width, which relies on this - // being a child not a dtype pointed node - virtual bool maybePointedTo() const override { return false; } - AstNode* elementsp() const { return op1p(); } -}; - -class AstUnsizedRange final : public AstNodeRange { - // Unsized range specification, for open arrays -public: - explicit AstUnsizedRange(FileLine* fl) - : ASTGEN_SUPER_UnsizedRange(fl) {} - ASTNODE_NODE_FUNCS(UnsizedRange) - virtual string emitC() { V3ERROR_NA_RETURN(""); } - virtual string emitVerilog() { return "[]"; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstWildcardRange final : public AstNodeRange { - // Wildcard range specification, for wildcard index type associative arrays -public: - explicit AstWildcardRange(FileLine* fl) - : ASTGEN_SUPER_WildcardRange(fl) {} - ASTNODE_NODE_FUNCS(WildcardRange) - virtual string emitC() { V3ERROR_NA_RETURN(""); } - virtual string emitVerilog() { return "[*]"; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstGatePin final : public AstNodeMath { - // Possibly expand a gate primitive input pin value to match the range of the gate primitive -public: - AstGatePin(FileLine* fl, AstNode* lhsp, AstRange* rangep) - : ASTGEN_SUPER_GatePin(fl) { - setOp1p(lhsp); - setOp2p(rangep); - } - ASTNODE_NODE_FUNCS(GatePin) - virtual string emitVerilog() override { return "%l"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - AstNode* exprp() const { return op1p(); } // op1 = Pin expression - AstRange* rangep() const { return VN_AS(op2p(), Range); } // op2 = Range of pin -}; - -//###################################################################### -// Classes - -class AstClassPackage final : public AstNodeModule { - // The static information portion of a class (treated similarly to a package) - AstClass* m_classp - = nullptr; // Class package this is under (weak pointer, hard link is other way) -public: - AstClassPackage(FileLine* fl, const string& name) - : ASTGEN_SUPER_ClassPackage(fl, name) {} - ASTNODE_NODE_FUNCS(ClassPackage) - virtual string verilogKwd() const override { return "classpackage"; } - virtual const char* broken() const override; - virtual void cloneRelink() override; - virtual bool timescaleMatters() const override { return false; } - AstClass* classp() const { return m_classp; } - void classp(AstClass* classp) { m_classp = classp; } -}; - -class AstClass final : public AstNodeModule { - // TYPES - using MemberNameMap = std::map; - // MEMBERS - MemberNameMap m_members; // Members or method children - AstClassPackage* m_classOrPackagep = nullptr; // Class package this is under - bool m_virtual = false; // Virtual class - bool m_extended = false; // Is extension or extended by other classes - void insertCache(AstNode* nodep); - -public: - AstClass(FileLine* fl, const string& name) - : ASTGEN_SUPER_Class(fl, name) {} - ASTNODE_NODE_FUNCS(Class) - virtual string verilogKwd() const override { return "class"; } - virtual bool maybePointedTo() const override { return true; } - virtual void dump(std::ostream& str) const override; - virtual const char* broken() const override { - BROKEN_BASE_RTN(AstNodeModule::broken()); - BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { - AstNodeModule::cloneRelink(); - if (m_classOrPackagep && m_classOrPackagep->clonep()) { - m_classOrPackagep = m_classOrPackagep->clonep(); - } - } - virtual bool timescaleMatters() const override { return false; } - // op1/op2/op3 in AstNodeModule - AstClassPackage* classOrPackagep() const { return m_classOrPackagep; } - void classOrPackagep(AstClassPackage* classpackagep) { m_classOrPackagep = classpackagep; } - AstNode* membersp() const { return stmtsp(); } // op2 = List of statements - void addMembersp(AstNode* nodep) { - insertCache(nodep); - addStmtp(nodep); - } - AstClassExtends* extendsp() const { return VN_AS(op4p(), ClassExtends); } - void extendsp(AstNode* nodep) { addNOp4p(nodep); } - void clearCache() { m_members.clear(); } - void repairCache(); - AstNode* findMember(const string& name) const { - const auto it = m_members.find(name); - return (it == m_members.end()) ? nullptr : it->second; - } - bool isExtended() const { return m_extended; } - void isExtended(bool flag) { m_extended = flag; } - bool isVirtual() const { return m_virtual; } - void isVirtual(bool flag) { m_virtual = flag; } - // Return true if this class is an extension of base class (SLOW) - // Accepts nullptrs - static bool isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp); -}; - -class AstClassExtends final : public AstNode { - // Children: List of AstParseRef for packages/classes - // during early parse, then moves to dtype -public: - AstClassExtends(FileLine* fl, AstNode* classOrPkgsp) - : ASTGEN_SUPER_ClassExtends(fl) { - setNOp2p(classOrPkgsp); // Only for parser - } - ASTNODE_NODE_FUNCS(ClassExtends) - virtual bool hasDType() const override { return true; } - virtual string verilogKwd() const override { return "extends"; } - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - AstNode* classOrPkgsp() const { return op2p(); } - AstClass* classp() const; // Class being extended (after link) -}; - -//###################################################################### -//==== Data Types - -class AstParamTypeDType final : public AstNodeDType { - // Parents: MODULE - // A parameter type statement; much like a var or typedef -private: - const VVarType m_varType; // Type of variable (for localparam vs. param) - string m_name; // Name of variable -public: - AstParamTypeDType(FileLine* fl, VVarType type, const string& name, VFlagChildDType, - AstNodeDType* dtp) - : ASTGEN_SUPER_ParamTypeDType(fl) - , m_varType{type} - , m_name{name} { - childDTypep(dtp); // Only for parser - dtypep(nullptr); // V3Width will resolve - } - ASTNODE_NODE_FUNCS(ParamTypeDType) - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - // op1 = Type assigning to - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const override { - return dtypep() ? dtypep() : childDTypep(); - } - virtual AstBasicDType* basicp() const override { return subDTypep()->basicp(); } - virtual AstNodeDType* skipRefp() const override { return subDTypep()->skipRefp(); } - virtual AstNodeDType* skipRefToConstp() const override { - return subDTypep()->skipRefToConstp(); - } - virtual AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); } - virtual bool similarDType(AstNodeDType* samep) const override { - const AstParamTypeDType* const sp = static_cast(samep); - return type() == samep->type() && sp - && this->subDTypep()->skipRefp()->similarDType(sp->subDTypep()->skipRefp()); - } - virtual int widthAlignBytes() const override { return dtypep()->widthAlignBytes(); } - virtual int widthTotalBytes() const override { return dtypep()->widthTotalBytes(); } - // METHODS - virtual string name() const override { return m_name; } - virtual bool maybePointedTo() const override { return true; } - virtual bool hasDType() const override { return true; } - virtual void name(const string& flag) override { m_name = flag; } - VVarType varType() const { return m_varType; } // * = Type of variable - bool isParam() const { return true; } - bool isGParam() const { return (varType() == VVarType::GPARAM); } - virtual bool isCompound() const override { - v3fatalSrc("call isCompound on subdata type, not reference"); - return false; - } -}; - -class AstTypedef final : public AstNode { -private: - string m_name; - bool m_attrPublic; - string m_tag; // Holds the string of the verilator tag -- used in XML output. -public: - AstTypedef(FileLine* fl, const string& name, AstNode* attrsp, VFlagChildDType, - AstNodeDType* dtp) - : ASTGEN_SUPER_Typedef(fl) - , m_name{name} { - childDTypep(dtp); // Only for parser - addAttrsp(attrsp); - dtypep(nullptr); // V3Width will resolve - m_attrPublic = false; - } - ASTNODE_NODE_FUNCS(Typedef) - virtual void dump(std::ostream& str) const override; - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - // op1 = Type assigning to - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } - void addAttrsp(AstNode* nodep) { addNOp4p(nodep); } - AstNode* attrsp() const { return op4p(); } // op4 = Attributes during early parse - // METHODS - virtual string name() const override { return m_name; } - virtual bool maybePointedTo() const override { return true; } - virtual bool hasDType() const override { return true; } - virtual void name(const string& flag) override { m_name = flag; } - bool attrPublic() const { return m_attrPublic; } - void attrPublic(bool flag) { m_attrPublic = flag; } - virtual void tag(const string& text) override { m_tag = text; } - virtual string tag() const override { return m_tag; } -}; - -class AstTypedefFwd final : public AstNode { - // Forward declaration of a type; stripped after netlist parsing is complete -private: - string m_name; - -public: - AstTypedefFwd(FileLine* fl, const string& name) - : ASTGEN_SUPER_TypedefFwd(fl) - , m_name{name} {} - ASTNODE_NODE_FUNCS(TypedefFwd) - // METHODS - virtual string name() const override { return m_name; } - virtual bool maybePointedTo() const override { return true; } -}; - -class AstDefImplicitDType final : public AstNodeDType { - // For parsing enum/struct/unions that are declared with a variable rather than typedef - // This allows "var enum {...} a,b" to share the enum definition for both variables - // After link, these become typedefs -private: - string m_name; - void* m_containerp; // In what scope is the name unique, so we can know what are duplicate - // definitions (arbitrary value) - const int m_uniqueNum; - -public: - AstDefImplicitDType(FileLine* fl, const string& name, void* containerp, VFlagChildDType, - AstNodeDType* dtp) - : ASTGEN_SUPER_DefImplicitDType(fl) - , m_name{name} - , m_containerp{containerp} - , m_uniqueNum{uniqueNumInc()} { - childDTypep(dtp); // Only for parser - dtypep(nullptr); // V3Width will resolve - } - ASTNODE_NODE_FUNCS(DefImplicitDType) - int uniqueNum() const { return m_uniqueNum; } - virtual bool same(const AstNode* samep) const override { - const AstDefImplicitDType* const sp = static_cast(samep); - return uniqueNum() == sp->uniqueNum(); - } - virtual bool similarDType(AstNodeDType* samep) const override { - return type() == samep->type() && same(samep); - } - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - // op1 = Range of variable - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const override { - return dtypep() ? dtypep() : childDTypep(); - } - void* containerp() const { return m_containerp; } - // METHODS - // op1 = Range of variable - AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } - virtual AstBasicDType* basicp() const override { return subDTypep()->basicp(); } - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { return dtypep()->widthAlignBytes(); } - virtual int widthTotalBytes() const override { return dtypep()->widthTotalBytes(); } - virtual string name() const override { return m_name; } - virtual void name(const string& flag) override { m_name = flag; } - virtual bool isCompound() const override { return false; } -}; - -class AstAssocArrayDType final : public AstNodeDType { - // Associative array data type, ie "[some_dtype]" - // Children: DTYPE (moved to refDTypep() in V3Width) - // Children: DTYPE (the key, which remains here as a pointer) -private: - AstNodeDType* m_refDTypep; // Elements of this type (after widthing) - AstNodeDType* m_keyDTypep; // Keys of this type (after widthing) -public: - AstAssocArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNodeDType* keyDtp) - : ASTGEN_SUPER_AssocArrayDType(fl) { - childDTypep(dtp); // Only for parser - keyChildDTypep(keyDtp); // Only for parser - refDTypep(nullptr); - keyDTypep(nullptr); - dtypep(nullptr); // V3Width will resolve - } - AstAssocArrayDType(FileLine* fl, AstNodeDType* dtp, AstNodeDType* keyDtp) - : ASTGEN_SUPER_AssocArrayDType(fl) { - refDTypep(dtp); - keyDTypep(keyDtp); - dtypep(dtp); - } - ASTNODE_NODE_FUNCS(AssocArrayDType) - virtual const char* broken() const override { - BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) - || (!m_refDTypep && childDTypep()))); - BROKEN_RTN(!((m_keyDTypep && !childDTypep() && m_keyDTypep->brokeExists()) - || (!m_keyDTypep && childDTypep()))); - return nullptr; - } - virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); - if (m_keyDTypep && m_keyDTypep->clonep()) m_keyDTypep = m_keyDTypep->clonep(); - } - virtual bool same(const AstNode* samep) const override { - const AstAssocArrayDType* const asamep = static_cast(samep); - if (!asamep->subDTypep()) return false; - if (!asamep->keyDTypep()) return false; - return (subDTypep() == asamep->subDTypep() && keyDTypep() == asamep->keyDTypep()); - } - virtual bool similarDType(AstNodeDType* samep) const override { - const AstAssocArrayDType* const asamep = static_cast(samep); - return type() == samep->type() && asamep->subDTypep() - && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); - } - virtual string prettyDTypeName() const override; - virtual void dumpSmall(std::ostream& str) const override; - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - virtual AstNodeDType* getChild2DTypep() const override { return keyChildDTypep(); } - // op1 = Range of variable - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const override { - return m_refDTypep ? m_refDTypep : childDTypep(); - } - void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } - virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } - virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } - virtual AstNodeDType* virtRefDType2p() const override { return m_keyDTypep; } - virtual void virtRefDType2p(AstNodeDType* nodep) override { keyDTypep(nodep); } - // - AstNodeDType* keyDTypep() const { return m_keyDTypep ? m_keyDTypep : keyChildDTypep(); } - void keyDTypep(AstNodeDType* nodep) { m_keyDTypep = nodep; } - // op1 = Range of variable - AstNodeDType* keyChildDTypep() const { return VN_AS(op2p(), NodeDType); } - void keyChildDTypep(AstNodeDType* nodep) { setOp2p(nodep); } - // METHODS - virtual AstBasicDType* basicp() const override { return nullptr; } - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } - virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } - virtual bool isCompound() const override { return true; } -}; - -class AstBracketArrayDType final : public AstNodeDType { - // Associative/Queue/Normal array data type, ie "[dtype_or_expr]" - // only for early parsing then becomes another data type - // Children: DTYPE (moved to refDTypep() in V3Width) - // Children: DTYPE (the key) -public: - AstBracketArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* elementsp) - : ASTGEN_SUPER_BracketArrayDType(fl) { - setOp1p(dtp); // Only for parser - setOp2p(elementsp); // Only for parser - } - ASTNODE_NODE_FUNCS(BracketArrayDType) - virtual bool similarDType(AstNodeDType* samep) const override { V3ERROR_NA_RETURN(false); } - // op1 = Range of variable - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - virtual AstNodeDType* subDTypep() const override { return childDTypep(); } - // op2 = Range of variable - AstNode* elementsp() const { return op2p(); } - // METHODS - // Will be removed in V3Width, which relies on this - // being a child not a dtype pointed node - virtual bool maybePointedTo() const override { return false; } - virtual AstBasicDType* basicp() const override { return nullptr; } - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { V3ERROR_NA_RETURN(0); } - virtual int widthTotalBytes() const override { V3ERROR_NA_RETURN(0); } - virtual bool isCompound() const override { return true; } -}; - -class AstDynArrayDType final : public AstNodeDType { - // Dynamic array data type, ie "[]" - // Children: DTYPE (moved to refDTypep() in V3Width) -private: - AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing) -public: - AstDynArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER_DynArrayDType(fl) { - childDTypep(dtp); // Only for parser - refDTypep(nullptr); - dtypep(nullptr); // V3Width will resolve - } - AstDynArrayDType(FileLine* fl, AstNodeDType* dtp) - : ASTGEN_SUPER_DynArrayDType(fl) { - refDTypep(dtp); - dtypep(nullptr); // V3Width will resolve - } - ASTNODE_NODE_FUNCS(DynArrayDType) - virtual const char* broken() const override { - BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) - || (!m_refDTypep && childDTypep()))); - return nullptr; - } - virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); - } - virtual bool same(const AstNode* samep) const override { - const AstAssocArrayDType* const asamep = static_cast(samep); - if (!asamep->subDTypep()) return false; - return subDTypep() == asamep->subDTypep(); - } - virtual bool similarDType(AstNodeDType* samep) const override { - const AstAssocArrayDType* const asamep = static_cast(samep); - return type() == samep->type() && asamep->subDTypep() - && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); - } - virtual string prettyDTypeName() const override; - virtual void dumpSmall(std::ostream& str) const override; - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - // op1 = Range of variable - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const override { - return m_refDTypep ? m_refDTypep : childDTypep(); - } - void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } - virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } - virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } - // METHODS - virtual AstBasicDType* basicp() const override { return nullptr; } - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } - virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } - virtual bool isCompound() const override { return true; } -}; - -class AstPackArrayDType final : public AstNodeArrayDType { - // Packed array data type, ie "some_dtype [2:0] var_name" - // Children: DTYPE (moved to refDTypep() in V3Width) - // Children: RANGE (array bounds) -public: - AstPackArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstRange* rangep) - : ASTGEN_SUPER_PackArrayDType(fl) { - childDTypep(dtp); // Only for parser - refDTypep(nullptr); - setOp2p(rangep); - dtypep(nullptr); // V3Width will resolve - const int width = subDTypep()->width() * rangep->elementsConst(); - widthForce(width, width); - } - AstPackArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep) - : ASTGEN_SUPER_PackArrayDType(fl) { - refDTypep(dtp); - setOp2p(rangep); - dtypep(this); - const int width = subDTypep()->width() * rangep->elementsConst(); - widthForce(width, width); - } - ASTNODE_NODE_FUNCS(PackArrayDType) - virtual string prettyDTypeName() const override; - virtual bool isCompound() const override { return false; } -}; - -class AstUnpackArrayDType final : public AstNodeArrayDType { - // Array data type, ie "some_dtype var_name [2:0]" - // Children: DTYPE (moved to refDTypep() in V3Width) - // Children: RANGE (array bounds) - bool m_isCompound = false; // Non-POD subDType, or parent requires compound -public: - AstUnpackArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstRange* rangep) - : ASTGEN_SUPER_UnpackArrayDType(fl) { - childDTypep(dtp); // Only for parser - refDTypep(nullptr); - setOp2p(rangep); - dtypep(nullptr); // V3Width will resolve - // For backward compatibility AstNodeArrayDType and others inherit - // width and signing from the subDType/base type - widthFromSub(subDTypep()); - } - AstUnpackArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep) - : ASTGEN_SUPER_UnpackArrayDType(fl) { - refDTypep(dtp); - setOp2p(rangep); - dtypep(this); - // For backward compatibility AstNodeArrayDType and others inherit - // width and signing from the subDType/base type - widthFromSub(subDTypep()); - } - ASTNODE_NODE_FUNCS(UnpackArrayDType) - virtual string prettyDTypeName() const override; - virtual bool same(const AstNode* samep) const override { - const AstUnpackArrayDType* const sp = static_cast(samep); - return m_isCompound == sp->m_isCompound; - } - // Outer dimension comes first. The first element is this node. - std::vector unpackDimensions(); - void isCompound(bool flag) { m_isCompound = flag; } - virtual bool isCompound() const override { return m_isCompound; } -}; - -class AstUnsizedArrayDType final : public AstNodeDType { - // Unsized/open-range Array data type, ie "some_dtype var_name []" - // Children: DTYPE (moved to refDTypep() in V3Width) -private: - AstNodeDType* m_refDTypep; // Elements of this type (after widthing) -public: - AstUnsizedArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER_UnsizedArrayDType(fl) { - childDTypep(dtp); // Only for parser - refDTypep(nullptr); - dtypep(nullptr); // V3Width will resolve - } - ASTNODE_NODE_FUNCS(UnsizedArrayDType) - virtual const char* broken() const override { - BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) - || (!m_refDTypep && childDTypep()))); - return nullptr; - } - virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); - } - virtual bool same(const AstNode* samep) const override { - const AstNodeArrayDType* const asamep = static_cast(samep); - if (!asamep->subDTypep()) return false; - return (subDTypep() == asamep->subDTypep()); - } - virtual bool similarDType(AstNodeDType* samep) const override { - const AstNodeArrayDType* const asamep = static_cast(samep); - return type() == samep->type() && asamep->subDTypep() - && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); - } - virtual void dumpSmall(std::ostream& str) const override; - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - // op1 = Range of variable - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const override { - return m_refDTypep ? m_refDTypep : childDTypep(); - } - void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } - virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } - virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } - // METHODS - virtual AstBasicDType* basicp() const override { return subDTypep()->basicp(); } - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } - virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } - virtual bool isCompound() const override { return true; } -}; - -class AstWildcardArrayDType final : public AstNodeDType { - // Wildcard index type associative array data type, ie "some_dtype var_name [*]" - // Children: DTYPE (moved to refDTypep() in V3Width) -private: - AstNodeDType* m_refDTypep; // Elements of this type (after widthing) -public: - AstWildcardArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER_WildcardArrayDType(fl) { - childDTypep(dtp); // Only for parser - refDTypep(nullptr); - dtypep(nullptr); // V3Width will resolve - } - ASTNODE_NODE_FUNCS(WildcardArrayDType) - virtual const char* broken() const override { - BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) - || (!m_refDTypep && childDTypep()))); - return nullptr; - } - virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); - } - virtual bool same(const AstNode* samep) const override { - const AstNodeArrayDType* const asamep = static_cast(samep); - if (!asamep->subDTypep()) return false; - return (subDTypep() == asamep->subDTypep()); - } - virtual bool similarDType(AstNodeDType* samep) const override { - const AstNodeArrayDType* const asamep = static_cast(samep); - return type() == samep->type() && asamep->subDTypep() - && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); - } - virtual void dumpSmall(std::ostream& str) const override; - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - // op1 = Range of variable - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const override { - return m_refDTypep ? m_refDTypep : childDTypep(); - } - void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } - virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } - virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } - // METHODS - virtual AstBasicDType* basicp() const override { return subDTypep()->basicp(); } - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { - return sizeof(std::map); - } - virtual int widthTotalBytes() const override { - return sizeof(std::map); - } - virtual bool isCompound() const override { return true; } -}; - -class AstBasicDType final : public AstNodeDType { - // Builtin atomic/vectored data type - // Children: RANGE (converted to constant in V3Width) -private: - struct Members { - VBasicDTypeKwd m_keyword; // (also in VBasicTypeKey) What keyword created basic type - VNumRange m_nrange; // (also in VBasicTypeKey) Numeric msb/lsb (if non-opaque keyword) - bool operator==(const Members& rhs) const { - return rhs.m_keyword == m_keyword && rhs.m_nrange == m_nrange; - } - } m; - // See also in AstNodeDType: m_width, m_widthMin, m_numeric(issigned) -public: - AstBasicDType(FileLine* fl, VBasicDTypeKwd kwd, const VSigning& signst = VSigning::NOSIGN) - : ASTGEN_SUPER_BasicDType(fl) { - init(kwd, signst, 0, -1, nullptr); - } - AstBasicDType(FileLine* fl, VFlagLogicPacked, int wantwidth) - : ASTGEN_SUPER_BasicDType(fl) { - init(VBasicDTypeKwd::LOGIC, VSigning::NOSIGN, wantwidth, -1, nullptr); - } - AstBasicDType(FileLine* fl, VFlagBitPacked, int wantwidth) - : ASTGEN_SUPER_BasicDType(fl) { - init(VBasicDTypeKwd::BIT, VSigning::NOSIGN, wantwidth, -1, nullptr); - } - AstBasicDType(FileLine* fl, VBasicDTypeKwd kwd, VSigning numer, int wantwidth, int widthmin) - : ASTGEN_SUPER_BasicDType(fl) { - init(kwd, numer, wantwidth, widthmin, nullptr); - } - AstBasicDType(FileLine* fl, VBasicDTypeKwd kwd, VSigning numer, VNumRange range, int widthmin) - : ASTGEN_SUPER_BasicDType(fl) { - init(kwd, numer, range.elements(), widthmin, nullptr); - m.m_nrange = range; // as init() presumes lsb==0, but range.lsb() might not be - } - // See also addRange in verilog.y -private: - void init(VBasicDTypeKwd kwd, VSigning numer, int wantwidth, int wantwidthmin, - AstRange* rangep) { - // wantwidth=0 means figure it out, but if a widthmin is >=0 - // we allow width 0 so that {{0{x}},y} works properly - // wantwidthmin=-1: default, use wantwidth if it is non zero - m.m_keyword = kwd; - // Implicitness: // "parameter X" is implicit and sized from initial - // value, "parameter reg x" not - if (keyword() == VBasicDTypeKwd::LOGIC_IMPLICIT) { - if (rangep || wantwidth) m.m_keyword = VBasicDTypeKwd::LOGIC; - } - if (numer == VSigning::NOSIGN) { - if (keyword().isSigned()) { - numer = VSigning::SIGNED; - } else if (keyword().isUnsigned()) { - numer = VSigning::UNSIGNED; - } - } - numeric(numer); - if (!rangep && (wantwidth || wantwidthmin >= 0)) { // Constant width - if (wantwidth > 1) m.m_nrange.init(wantwidth - 1, 0, false); - const int wmin = wantwidthmin >= 0 ? wantwidthmin : wantwidth; - widthForce(wantwidth, wmin); - } else if (!rangep) { // Set based on keyword properties - // V3Width will pull from this width - if (keyword().width() > 1 && !isOpaque()) { - m.m_nrange.init(keyword().width() - 1, 0, false); - } - widthForce(keyword().width(), keyword().width()); - } else { - widthForce(rangep->elementsConst(), - rangep->elementsConst()); // Maybe unknown if parameters underneath it - } - setNOp1p(rangep); - dtypep(this); - } - -public: - ASTNODE_NODE_FUNCS(BasicDType) - virtual void dump(std::ostream& str) const override; - // width/widthMin/numeric compared elsewhere - virtual bool same(const AstNode* samep) const override { - const AstBasicDType* const sp = static_cast(samep); - return m == sp->m; - } - virtual bool similarDType(AstNodeDType* samep) const override { - return type() == samep->type() && same(samep); - } - virtual string name() const override { return m.m_keyword.ascii(); } - virtual string prettyDTypeName() const override; - virtual const char* broken() const override { - BROKEN_RTN(dtypep() != this); - return nullptr; - } - AstRange* rangep() const { return VN_AS(op1p(), Range); } // op1 = Range of variable - void rangep(AstRange* nodep) { setNOp1p(nodep); } - void setSignedState(const VSigning& signst) { - // Note NOSIGN does NOT change the state; this is required by the parser - if (signst == VSigning::UNSIGNED) { - numeric(signst); - } else if (signst == VSigning::SIGNED) { - numeric(signst); - } - } - // METHODS - virtual AstBasicDType* basicp() const override { return (AstBasicDType*)this; } - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) - virtual int widthAlignBytes() const override; - // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... - virtual int widthTotalBytes() const override; - virtual bool isFourstate() const override { return keyword().isFourstate(); } - VBasicDTypeKwd keyword() const { // Avoid using - use isSomething accessors instead - return m.m_keyword; - } - bool isBitLogic() const { return keyword().isBitLogic(); } - bool isDouble() const { return keyword().isDouble(); } - bool isEventValue() const { return keyword().isEventValue(); } - bool isOpaque() const { return keyword().isOpaque(); } - bool isString() const { return keyword().isString(); } - bool isZeroInit() const { return keyword().isZeroInit(); } - bool isRanged() const { return rangep() || m.m_nrange.ranged(); } - bool isDpiBitVec() const { // DPI uses svBitVecVal - return keyword() == VBasicDTypeKwd::BIT && isRanged(); - } - bool isDpiLogicVec() const { // DPI uses svLogicVecVal - return keyword().isFourstate() && !(keyword() == VBasicDTypeKwd::LOGIC && !isRanged()); - } - bool isDpiPrimitive() const { // DPI uses a primitive type - return !isDpiBitVec() && !isDpiLogicVec(); - } - // Generally the lo/hi/left/right funcs should be used instead of nrange() - const VNumRange& nrange() const { return m.m_nrange; } - int hi() const { return (rangep() ? rangep()->hiConst() : m.m_nrange.hi()); } - int lo() const { return (rangep() ? rangep()->loConst() : m.m_nrange.lo()); } - int elements() const { return (rangep() ? rangep()->elementsConst() : m.m_nrange.elements()); } - int left() const { return littleEndian() ? lo() : hi(); } // How to show a declaration - int right() const { return littleEndian() ? hi() : lo(); } - bool littleEndian() const { - return (rangep() ? rangep()->littleEndian() : m.m_nrange.littleEndian()); - } - bool implicit() const { return keyword() == VBasicDTypeKwd::LOGIC_IMPLICIT; } - VNumRange declRange() const { return isRanged() ? VNumRange{left(), right()} : VNumRange{}; } - void cvtRangeConst() { // Convert to smaller representation - if (rangep() && VN_IS(rangep()->leftp(), Const) && VN_IS(rangep()->rightp(), Const)) { - m.m_nrange = VNumRange{rangep()->leftConst(), rangep()->rightConst()}; - rangep()->unlinkFrBackWithNext()->deleteTree(); - rangep(nullptr); - } - } - virtual bool isCompound() const override { return isString(); } -}; - -class AstConstDType final : public AstNodeDType { - // const data type, ie "const some_dtype var_name [2:0]" - // ConstDType are removed in V3LinkLValue and become AstVar::isConst. - // When more generic types are supported AstConstDType will be propagated further. -private: - AstNodeDType* m_refDTypep = nullptr; // Inherit from this base data type -public: - AstConstDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER_ConstDType(fl) { - childDTypep(dtp); // Only for parser - refDTypep(nullptr); // V3Width will resolve - dtypep(nullptr); // V3Width will resolve - widthFromSub(subDTypep()); - } - ASTNODE_NODE_FUNCS(ConstDType) - virtual const char* broken() const override { - BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) - || (!m_refDTypep && childDTypep()))); - return nullptr; - } - virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); - } - virtual bool same(const AstNode* samep) const override { - const AstConstDType* const sp = static_cast(samep); - return (m_refDTypep == sp->m_refDTypep); - } - virtual bool similarDType(AstNodeDType* samep) const override { - return skipRefp()->similarDType(samep->skipRefp()); - } - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - // op1 = Range of variable - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const override { - return m_refDTypep ? m_refDTypep : childDTypep(); - } - void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } - virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } - virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } - // METHODS - virtual AstBasicDType* basicp() const override { return subDTypep()->basicp(); } - virtual AstNodeDType* skipRefp() const override { return subDTypep()->skipRefp(); } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); } - virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } - virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } - virtual bool isCompound() const override { - v3fatalSrc("call isCompound on subdata type, not reference"); - return false; - } -}; - -class AstClassRefDType final : public AstNodeDType { - // Reference to a class - // Children: PINs (for parameter settings) -private: - AstClass* m_classp; // data type pointed to, BELOW the AstTypedef - AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy -public: - AstClassRefDType(FileLine* fl, AstClass* classp, AstNode* paramsp) - : ASTGEN_SUPER_ClassRefDType(fl) - , m_classp{classp} { - dtypep(this); - addNOp4p(paramsp); - } - ASTNODE_NODE_FUNCS(ClassRefDType) - // METHODS - virtual const char* broken() const override { - BROKEN_RTN(m_classp && !m_classp->brokeExists()); - BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { - if (m_classp && m_classp->clonep()) m_classp = m_classp->clonep(); - if (m_classOrPackagep && m_classOrPackagep->clonep()) { - m_classOrPackagep = m_classOrPackagep->clonep(); - } - } - virtual bool same(const AstNode* samep) const override { - const AstClassRefDType* const asamep = static_cast(samep); - return (m_classp == asamep->m_classp && m_classOrPackagep == asamep->m_classOrPackagep); - } - virtual bool similarDType(AstNodeDType* samep) const override { - return this == samep || (type() == samep->type() && same(samep)); - } - virtual void dump(std::ostream& str = std::cout) const override; - virtual void dumpSmall(std::ostream& str) const override; - virtual string name() const override { return classp() ? classp()->name() : ""; } - virtual AstBasicDType* basicp() const override { return nullptr; } - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { return 0; } - virtual int widthTotalBytes() const override { return 0; } - virtual AstNodeDType* virtRefDTypep() const override { return nullptr; } - virtual void virtRefDTypep(AstNodeDType* nodep) override {} - virtual AstNodeDType* subDTypep() const override { return nullptr; } - AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } - void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } - AstClass* classp() const { return m_classp; } - void classp(AstClass* nodep) { m_classp = nodep; } - AstPin* paramsp() const { return VN_AS(op4p(), Pin); } - virtual bool isCompound() const override { return true; } -}; - -class AstIfaceRefDType final : public AstNodeDType { - // Reference to an interface, either for a port, or inside parent cell -private: - FileLine* m_modportFileline; // Where modport token was - string m_cellName; // "" = no cell, such as when connects to 'input' iface - string m_ifaceName; // Interface name - string m_modportName; // "" = no modport - AstIface* m_ifacep = nullptr; // Pointer to interface; note cellp() should override - AstCell* m_cellp = nullptr; // When exact parent cell known; not a guess - AstModport* m_modportp = nullptr; // nullptr = unlinked or no modport -public: - AstIfaceRefDType(FileLine* fl, const string& cellName, const string& ifaceName) - : ASTGEN_SUPER_IfaceRefDType(fl) - , m_modportFileline{nullptr} - , m_cellName{cellName} - , m_ifaceName{ifaceName} - , m_modportName{""} {} - AstIfaceRefDType(FileLine* fl, FileLine* modportFl, const string& cellName, - const string& ifaceName, const string& modport) - : ASTGEN_SUPER_IfaceRefDType(fl) - , m_modportFileline{modportFl} - , m_cellName{cellName} - , m_ifaceName{ifaceName} - , m_modportName{modport} {} - ASTNODE_NODE_FUNCS(IfaceRefDType) - // METHODS - virtual const char* broken() const override; - virtual void dump(std::ostream& str = std::cout) const override; - virtual void dumpSmall(std::ostream& str) const override; - virtual void cloneRelink() override; - virtual AstBasicDType* basicp() const override { return nullptr; } - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual bool similarDType(AstNodeDType* samep) const override { return this == samep; } - virtual int widthAlignBytes() const override { return 1; } - virtual int widthTotalBytes() const override { return 1; } - FileLine* modportFileline() const { return m_modportFileline; } - string cellName() const { return m_cellName; } - void cellName(const string& name) { m_cellName = name; } - string ifaceName() const { return m_ifaceName; } - void ifaceName(const string& name) { m_ifaceName = name; } - string modportName() const { return m_modportName; } - AstIface* ifaceViaCellp() const; // Use cellp or ifacep - AstIface* ifacep() const { return m_ifacep; } - void ifacep(AstIface* nodep) { m_ifacep = nodep; } - AstCell* cellp() const { return m_cellp; } - void cellp(AstCell* nodep) { m_cellp = nodep; } - AstModport* modportp() const { return m_modportp; } - void modportp(AstModport* modportp) { m_modportp = modportp; } - bool isModport() { return !m_modportName.empty(); } - virtual bool isCompound() const override { return true; } // But not relevant -}; - -class AstQueueDType final : public AstNodeDType { - // Queue array data type, ie "[ $ ]" - // Children: DTYPE (moved to refDTypep() in V3Width) -private: - AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing) -public: - AstQueueDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* boundp) - : ASTGEN_SUPER_QueueDType(fl) { - setNOp2p(boundp); - childDTypep(dtp); // Only for parser - refDTypep(nullptr); - dtypep(nullptr); // V3Width will resolve - } - AstQueueDType(FileLine* fl, AstNodeDType* dtp, AstNode* boundp) - : ASTGEN_SUPER_QueueDType(fl) { - setNOp2p(boundp); - refDTypep(dtp); - dtypep(dtp); - } - ASTNODE_NODE_FUNCS(QueueDType) - virtual const char* broken() const override { - BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) - || (!m_refDTypep && childDTypep()))); - return nullptr; - } - virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); - } - virtual bool same(const AstNode* samep) const override { - const AstQueueDType* const asamep = static_cast(samep); - if (!asamep->subDTypep()) return false; - return (subDTypep() == asamep->subDTypep()); - } - virtual bool similarDType(AstNodeDType* samep) const override { - const AstQueueDType* const asamep = static_cast(samep); - return type() == samep->type() && asamep->subDTypep() - && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); - } - virtual void dumpSmall(std::ostream& str) const override; - virtual string prettyDTypeName() const override; - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - // op1 = Range of variable - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const override { - return m_refDTypep ? m_refDTypep : childDTypep(); - } - void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } - AstNode* boundp() const { return op2p(); } // op2 = Bound, nullptr = none - void boundp(AstNode* nodep) { setNOp2p(nodep); } - int boundConst() const { - AstConst* const constp = VN_CAST(boundp(), Const); - return (constp ? constp->toSInt() : 0); - } - virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } - virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } - // METHODS - virtual AstBasicDType* basicp() const override { return nullptr; } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } - virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } - virtual bool isCompound() const override { return true; } -}; - -class AstRefDType final : public AstNodeDType { -private: - // Pre-Width must reference the Typeref, not what it points to, as some child - // types like AstBracketArrayType will disappear and can't lose the handle - AstTypedef* m_typedefp = nullptr; // referenced type - // Post-width typedefs are removed and point to type directly - AstNodeDType* m_refDTypep = nullptr; // data type pointed to, BELOW the AstTypedef - string m_name; // Name of an AstTypedef - AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy -public: - AstRefDType(FileLine* fl, const string& name) - : ASTGEN_SUPER_RefDType(fl) - , m_name{name} {} - AstRefDType(FileLine* fl, const string& name, AstNode* classOrPackagep, AstNode* paramsp) - : ASTGEN_SUPER_RefDType(fl) - , m_name{name} { - setNOp3p(classOrPackagep); - addNOp4p(paramsp); - } - class FlagTypeOfExpr {}; // type(expr) for parser only - AstRefDType(FileLine* fl, FlagTypeOfExpr, AstNode* typeofp) - : ASTGEN_SUPER_RefDType(fl) { - setOp2p(typeofp); - } - ASTNODE_NODE_FUNCS(RefDType) - // METHODS - virtual const char* broken() const override { - BROKEN_RTN(m_typedefp && !m_typedefp->brokeExists()); - BROKEN_RTN(m_refDTypep && !m_refDTypep->brokeExists()); - BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { - if (m_typedefp && m_typedefp->clonep()) m_typedefp = m_typedefp->clonep(); - if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); - if (m_classOrPackagep && m_classOrPackagep->clonep()) { - m_classOrPackagep = m_classOrPackagep->clonep(); - } - } - virtual bool same(const AstNode* samep) const override { - const AstRefDType* const asamep = static_cast(samep); - return (m_typedefp == asamep->m_typedefp && m_refDTypep == asamep->m_refDTypep - && m_name == asamep->m_name && m_classOrPackagep == asamep->m_classOrPackagep); - } - virtual bool similarDType(AstNodeDType* samep) const override { - return skipRefp()->similarDType(samep->skipRefp()); - } - virtual void dump(std::ostream& str = std::cout) const override; - virtual string name() const override { return m_name; } - virtual string prettyDTypeName() const override { - return subDTypep() ? subDTypep()->name() : prettyName(); - } - virtual AstBasicDType* basicp() const override { - return subDTypep() ? subDTypep()->basicp() : nullptr; - } - virtual AstNodeDType* subDTypep() const override { - if (typedefp()) return typedefp()->subDTypep(); - return refDTypep(); // Maybe nullptr - } - virtual AstNodeDType* skipRefp() const override { - // Skip past both the Ref and the Typedef - if (subDTypep()) { - return subDTypep()->skipRefp(); - } else { - v3fatalSrc("Typedef not linked"); - return nullptr; - } - } - virtual AstNodeDType* skipRefToConstp() const override { - if (subDTypep()) { - return subDTypep()->skipRefToConstp(); - } else { - v3fatalSrc("Typedef not linked"); - return nullptr; - } - } - virtual AstNodeDType* skipRefToEnump() const override { - if (subDTypep()) { - return subDTypep()->skipRefToEnump(); - } else { - v3fatalSrc("Typedef not linked"); - return nullptr; - } - } - virtual int widthAlignBytes() const override { return dtypeSkipRefp()->widthAlignBytes(); } - virtual int widthTotalBytes() const override { return dtypeSkipRefp()->widthTotalBytes(); } - virtual void name(const string& flag) override { m_name = flag; } - // op1 = Range of variable - AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } - AstTypedef* typedefp() const { return m_typedefp; } - void typedefp(AstTypedef* nodep) { m_typedefp = nodep; } - AstNodeDType* refDTypep() const { return m_refDTypep; } - void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } - virtual AstNodeDType* virtRefDTypep() const override { return refDTypep(); } - virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } - AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } - void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } - AstNode* typeofp() const { return op2p(); } - AstNode* classOrPackageOpp() const { return op3p(); } - AstPin* paramsp() const { return VN_AS(op4p(), Pin); } - virtual bool isCompound() const override { - v3fatalSrc("call isCompound on subdata type, not reference"); - return false; - } -}; - -class AstStructDType final : public AstNodeUOrStructDType { -public: - // VSigning below is mispurposed to indicate if packed or not - AstStructDType(FileLine* fl, VSigning numericUnpack) - : ASTGEN_SUPER_StructDType(fl, numericUnpack) {} - ASTNODE_NODE_FUNCS(StructDType) - virtual string verilogKwd() const override { return "struct"; } -}; - -class AstUnionDType final : public AstNodeUOrStructDType { -public: - // UNSUP: bool isTagged; - // VSigning below is mispurposed to indicate if packed or not - AstUnionDType(FileLine* fl, VSigning numericUnpack) - : ASTGEN_SUPER_UnionDType(fl, numericUnpack) {} - ASTNODE_NODE_FUNCS(UnionDType) - virtual string verilogKwd() const override { return "union"; } -}; - -class AstMemberDType final : public AstNodeDType { - // A member of a struct/union - // PARENT: AstNodeUOrStructDType -private: - AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing) - string m_name; // Name of variable - string m_tag; // Holds the string of the verilator tag -- used in XML output. - int m_lsb = -1; // Within this level's packed struct, the LSB of the first bit of the member - // UNSUP: int m_randType; // Randomization type (IEEE) -public: - AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER_MemberDType(fl) - , m_name{name} { - childDTypep(dtp); // Only for parser - dtypep(nullptr); // V3Width will resolve - refDTypep(nullptr); - } - AstMemberDType(FileLine* fl, const string& name, AstNodeDType* dtp) - : ASTGEN_SUPER_MemberDType(fl) - , m_name{name} { - UASSERT(dtp, "AstMember created with no dtype"); - refDTypep(dtp); - dtypep(this); - widthFromSub(subDTypep()); - } - ASTNODE_NODE_FUNCS(MemberDType) - virtual string name() const override { return m_name; } // * = Var name - virtual bool hasDType() const override { return true; } - virtual bool maybePointedTo() const override { return true; } - virtual const char* broken() const override { - BROKEN_RTN(m_refDTypep && !m_refDTypep->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); - } - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - // op1 = Range of variable - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const override { - return m_refDTypep ? m_refDTypep : childDTypep(); - } - void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } - virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } - virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } - virtual bool similarDType(AstNodeDType* samep) const override { return this == samep; } - // - // (Slow) recurse down to find basic data type (Note don't need virtual - - // AstVar isn't a NodeDType) - virtual AstBasicDType* basicp() const override { return subDTypep()->basicp(); } - // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType) - AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } - virtual AstNodeDType* skipRefp() const override { return subDTypep()->skipRefp(); } - virtual AstNodeDType* skipRefToConstp() const override { - return subDTypep()->skipRefToConstp(); - } - virtual AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); } - // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) - virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } - // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... - virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } - // METHODS - virtual void name(const string& name) override { m_name = name; } - virtual void tag(const string& text) override { m_tag = text; } - virtual string tag() const override { return m_tag; } - int lsb() const { return m_lsb; } - void lsb(int lsb) { m_lsb = lsb; } - virtual bool isCompound() const override { - v3fatalSrc("call isCompound on subdata type, not reference"); - return false; - } -}; - -class AstEmptyQueueDType final : public AstNodeDType { - // For EmptyQueue -public: - explicit AstEmptyQueueDType(FileLine* fl) - : ASTGEN_SUPER_EmptyQueueDType(fl) { - dtypep(this); - } - ASTNODE_NODE_FUNCS(EmptyQueueDType) - virtual void dumpSmall(std::ostream& str) const override; - virtual bool hasDType() const override { return true; } - virtual bool maybePointedTo() const override { return true; } - virtual bool undead() const override { return true; } - virtual AstNodeDType* subDTypep() const override { return nullptr; } - virtual AstNodeDType* virtRefDTypep() const override { return nullptr; } - virtual void virtRefDTypep(AstNodeDType* nodep) override {} - virtual bool similarDType(AstNodeDType* samep) const override { return this == samep; } - virtual AstBasicDType* basicp() const override { return nullptr; } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { return 1; } - virtual int widthTotalBytes() const override { return 1; } - virtual bool isCompound() const override { return false; } -}; - -class AstVoidDType final : public AstNodeDType { - // For e.g. a function returning void -public: - explicit AstVoidDType(FileLine* fl) - : ASTGEN_SUPER_VoidDType(fl) { - dtypep(this); - } - ASTNODE_NODE_FUNCS(VoidDType) - virtual void dumpSmall(std::ostream& str) const override; - virtual bool hasDType() const override { return true; } - virtual bool maybePointedTo() const override { return true; } - virtual bool undead() const override { return true; } - virtual AstNodeDType* subDTypep() const override { return nullptr; } - virtual AstNodeDType* virtRefDTypep() const override { return nullptr; } - virtual void virtRefDTypep(AstNodeDType* nodep) override {} - virtual bool similarDType(AstNodeDType* samep) const override { return this == samep; } - virtual AstBasicDType* basicp() const override { return nullptr; } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { return 1; } - virtual int widthTotalBytes() const override { return 1; } - virtual bool isCompound() const override { return false; } -}; - -class AstEnumItem final : public AstNode { -private: - string m_name; - -public: - // Parents: ENUM - AstEnumItem(FileLine* fl, const string& name, AstNode* rangep, AstNode* initp) - : ASTGEN_SUPER_EnumItem(fl) - , m_name{name} { - addNOp1p(rangep); - addNOp2p(initp); - } - ASTNODE_NODE_FUNCS(EnumItem) - virtual string name() const override { return m_name; } - virtual bool maybePointedTo() const override { return true; } - virtual bool hasDType() const override { return true; } - virtual void name(const string& flag) override { m_name = flag; } - AstRange* rangep() const { return VN_AS(op1p(), Range); } // op1 = Range for name appending - void rangep(AstRange* nodep) { addOp1p(nodep); } - AstNode* valuep() const { return op2p(); } // op2 = Value - void valuep(AstNode* nodep) { addOp2p(nodep); } -}; - -class AstEnumItemRef final : public AstNodeMath { -private: - AstEnumItem* m_itemp; // [AfterLink] Pointer to item - AstNodeModule* m_classOrPackagep; // Package hierarchy -public: - AstEnumItemRef(FileLine* fl, AstEnumItem* itemp, AstNodeModule* classOrPackagep) - : ASTGEN_SUPER_EnumItemRef(fl) - , m_itemp{itemp} - , m_classOrPackagep{classOrPackagep} { - dtypeFrom(m_itemp); - } - ASTNODE_NODE_FUNCS(EnumItemRef) - virtual void dump(std::ostream& str) const override; - virtual string name() const override { return itemp()->name(); } - virtual int instrCount() const override { return 0; } - virtual const char* broken() const override { - BROKEN_RTN(m_itemp && !m_itemp->brokeExists()); - BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { - if (m_itemp->clonep()) m_itemp = m_itemp->clonep(); - } - virtual bool same(const AstNode* samep) const override { - const AstEnumItemRef* const sp = static_cast(samep); - return itemp() == sp->itemp(); - } - AstEnumItem* itemp() const { return m_itemp; } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } - void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } -}; - -class AstEnumDType final : public AstNodeDType { - // Parents: TYPEDEF/MODULE - // Children: ENUMVALUEs -private: - string m_name; // Name from upper typedef, if any - AstNodeDType* m_refDTypep = nullptr; // Elements are of this type after V3Width - const int m_uniqueNum = 0; - -public: - AstEnumDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* itemsp) - : ASTGEN_SUPER_EnumDType(fl) - , m_uniqueNum{uniqueNumInc()} { - childDTypep(dtp); // Only for parser - refDTypep(nullptr); - addNOp2p(itemsp); - dtypep(nullptr); // V3Width will resolve - widthFromSub(subDTypep()); - } - ASTNODE_NODE_FUNCS(EnumDType) - virtual const char* broken() const override { - BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) - || (!m_refDTypep && childDTypep()))); - return nullptr; - } - virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); - } - int uniqueNum() const { return m_uniqueNum; } - virtual bool same(const AstNode* samep) const override { - const AstEnumDType* const sp = static_cast(samep); - return uniqueNum() == sp->uniqueNum(); - } - virtual bool similarDType(AstNodeDType* samep) const override { return this == samep; } - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } // op1 = Data type - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - // op1 = Range of variable - virtual AstNodeDType* subDTypep() const override { - return m_refDTypep ? m_refDTypep : childDTypep(); - } - void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } - virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } - virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } - virtual string name() const override { return m_name; } - virtual void name(const string& flag) override { m_name = flag; } - AstEnumItem* itemsp() const { return VN_AS(op2p(), EnumItem); } // op2 = AstEnumItem's - // METHODS - virtual AstBasicDType* basicp() const override { return subDTypep()->basicp(); } - virtual AstNodeDType* skipRefp() const override { return subDTypep()->skipRefp(); } - virtual AstNodeDType* skipRefToConstp() const override { - return subDTypep()->skipRefToConstp(); - } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } - virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } - int itemCount() const { - size_t count = 0; - for (AstNode* itemp = itemsp(); itemp; itemp = itemp->nextp()) count++; - return count; - } - virtual bool isCompound() const override { return false; } -}; - -class AstParseTypeDType final : public AstNodeDType { - // Parents: VAR - // During parsing, this indicates the type of a parameter is a "parameter type" - // e.g. the data type is a container of any data type -public: - explicit AstParseTypeDType(FileLine* fl) - : ASTGEN_SUPER_ParseTypeDType(fl) {} - ASTNODE_NODE_FUNCS(ParseTypeDType) - AstNodeDType* dtypep() const { return nullptr; } - // METHODS - virtual bool similarDType(AstNodeDType* samep) const override { return this == samep; } - virtual AstBasicDType* basicp() const override { return nullptr; } - virtual AstNodeDType* skipRefp() const override { return nullptr; } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } - // cppcheck-suppress csyleCast - virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } - virtual int widthAlignBytes() const override { return 0; } - virtual int widthTotalBytes() const override { return 0; } - virtual bool isCompound() const override { - v3fatalSrc("call isCompound on subdata type, not reference"); - return false; - } -}; - -//###################################################################### - -class AstArraySel final : public AstNodeSel { - // Parents: math|stmt - // Children: varref|arraysel, math -private: - void init(AstNode* fromp) { - if (fromp && VN_IS(fromp->dtypep()->skipRefp(), NodeArrayDType)) { - // Strip off array to find what array references - dtypeFrom(VN_AS(fromp->dtypep()->skipRefp(), NodeArrayDType)->subDTypep()); - } - } - -public: - AstArraySel(FileLine* fl, AstNode* fromp, AstNode* bitp) - : ASTGEN_SUPER_ArraySel(fl, fromp, bitp) { - init(fromp); - } - AstArraySel(FileLine* fl, AstNode* fromp, int bit) - : ASTGEN_SUPER_ArraySel(fl, fromp, new AstConst(fl, bit)) { - init(fromp); - } - ASTNODE_NODE_FUNCS(ArraySel) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstArraySel(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - V3ERROR_NA; /* How can from be a const? */ - } - virtual string emitVerilog() override { return "%k(%l%f[%r])"; } - virtual string emitC() override { return "%li%k[%ri]"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool isGateOptimizable() const override { - return true; - } // esp for V3Const::ifSameAssign - virtual bool isPredictOptimizable() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } - // Special operators - // Return base var (or const) nodep dereferences - static AstNode* baseFromp(AstNode* nodep, bool overMembers); -}; - -class AstAssocSel final : public AstNodeSel { - // Parents: math|stmt - // Children: varref|arraysel, math -private: - void init(AstNode* fromp) { - if (fromp && VN_IS(fromp->dtypep()->skipRefp(), AssocArrayDType)) { - // Strip off array to find what array references - dtypeFrom(VN_AS(fromp->dtypep()->skipRefp(), AssocArrayDType)->subDTypep()); - } - } - -public: - AstAssocSel(FileLine* fl, AstNode* fromp, AstNode* bitp) - : ASTGEN_SUPER_AssocSel(fl, fromp, bitp) { - init(fromp); - } - ASTNODE_NODE_FUNCS(AssocSel) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAssocSel(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - V3ERROR_NA; - } - virtual string emitVerilog() override { return "%k(%l%f[%r])"; } - virtual string emitC() override { return "%li%k[%ri]"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool isGateOptimizable() const override { - return true; - } // esp for V3Const::ifSameAssign - virtual bool isPredictOptimizable() const override { return false; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } -}; - -class AstWildcardSel final : public AstNodeSel { - // Parents: math|stmt - // Children: varref|arraysel, math -private: - void init(AstNode* fromp) { - if (fromp && VN_IS(fromp->dtypep()->skipRefp(), WildcardArrayDType)) { - // Strip off array to find what array references - dtypeFrom(VN_AS(fromp->dtypep()->skipRefp(), WildcardArrayDType)->subDTypep()); - } - } - -public: - AstWildcardSel(FileLine* fl, AstNode* fromp, AstNode* bitp) - : ASTGEN_SUPER_WildcardSel(fl, fromp, bitp) { - init(fromp); - } - ASTNODE_NODE_FUNCS(WildcardSel) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstWildcardSel{this->fileline(), lhsp, rhsp}; - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - V3ERROR_NA; - } - virtual string emitVerilog() override { return "%k(%l%f[%r])"; } - virtual string emitC() override { return "%li%k[%ri]"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool isGateOptimizable() const override { - return true; - } // esp for V3Const::ifSameAssign - virtual bool isPredictOptimizable() const override { return false; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } -}; - -class AstWordSel final : public AstNodeSel { - // Select a single word from a multi-word wide value -public: - AstWordSel(FileLine* fl, AstNode* fromp, AstNode* bitp) - : ASTGEN_SUPER_WordSel(fl, fromp, bitp) { - dtypeSetUInt32(); // Always used on WData arrays so returns edata size - } - ASTNODE_NODE_FUNCS(WordSel) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstWordSel(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit) override { - V3ERROR_NA; - } - virtual string emitVerilog() override { return "%k(%l%f[%r])"; } - virtual string emitC() override { - return "%li[%ri]"; - } // Not %k, as usually it's a small constant rhsp - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstSelLoopVars final : public AstNode { - // Parser only concept "[id, id, id]" for a foreach statement - // Unlike normal selects elements is a list -public: - AstSelLoopVars(FileLine* fl, AstNode* fromp, AstNode* elementsp) - : ASTGEN_SUPER_SelLoopVars(fl) { - setOp1p(fromp); - addNOp2p(elementsp); - } - ASTNODE_NODE_FUNCS(SelLoopVars) - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual bool maybePointedTo() const override { return false; } - AstNode* fromp() const { return op1p(); } - void fromp(AstNode* nodep) { setOp1p(nodep); } - AstNode* elementsp() const { return op2p(); } -}; - -class AstSelExtract final : public AstNodePreSel { - // Range extraction, gets replaced with AstSel -public: - AstSelExtract(FileLine* fl, AstNode* fromp, AstNode* msbp, AstNode* lsbp) - : ASTGEN_SUPER_SelExtract(fl, fromp, msbp, lsbp) {} - ASTNODE_NODE_FUNCS(SelExtract) - AstNode* leftp() const { return rhsp(); } - AstNode* rightp() const { return thsp(); } -}; - -class AstSelBit final : public AstNodePreSel { - // Single bit range extraction, perhaps with non-constant selection or array selection - // Gets replaced during link with AstArraySel or AstSel -public: - AstSelBit(FileLine* fl, AstNode* fromp, AstNode* bitp) - : ASTGEN_SUPER_SelBit(fl, fromp, bitp, nullptr) { - UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, - "not coded to create after dtypes resolved"); - } - ASTNODE_NODE_FUNCS(SelBit) - AstNode* bitp() const { return rhsp(); } -}; - -class AstSelPlus final : public AstNodePreSel { - // +: range extraction, perhaps with non-constant selection - // Gets replaced during link with AstSel -public: - AstSelPlus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp) - : ASTGEN_SUPER_SelPlus(fl, fromp, bitp, widthp) {} - ASTNODE_NODE_FUNCS(SelPlus) - AstNode* bitp() const { return rhsp(); } - AstNode* widthp() const { return thsp(); } -}; - -class AstSelMinus final : public AstNodePreSel { - // -: range extraction, perhaps with non-constant selection - // Gets replaced during link with AstSel -public: - AstSelMinus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp) - : ASTGEN_SUPER_SelMinus(fl, fromp, bitp, widthp) {} - ASTNODE_NODE_FUNCS(SelMinus) - AstNode* bitp() const { return rhsp(); } - AstNode* widthp() const { return thsp(); } -}; - -class AstSel final : public AstNodeTriop { - // Multiple bit range extraction - // Parents: math|stmt - // Children: varref|arraysel, math, constant math - // Tempting to have an access() style method here as LHS selects are quite - // different, but that doesn't play well with V3Inst and bidirects which don't know direction -private: - VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid - int m_declElWidth; // If a packed array, the number of bits per element -public: - AstSel(FileLine* fl, AstNode* fromp, AstNode* lsbp, AstNode* widthp) - : ASTGEN_SUPER_Sel(fl, fromp, lsbp, widthp) - , m_declElWidth{1} { - if (VN_IS(widthp, Const)) { - dtypeSetLogicSized(VN_AS(widthp, Const)->toUInt(), VSigning::UNSIGNED); - } - } - AstSel(FileLine* fl, AstNode* fromp, int lsb, int bitwidth) - : ASTGEN_SUPER_Sel(fl, fromp, new AstConst(fl, lsb), new AstConst(fl, bitwidth)) - , m_declElWidth{1} { - dtypeSetLogicSized(bitwidth, VSigning::UNSIGNED); - } - ASTNODE_NODE_FUNCS(Sel) - virtual void dump(std::ostream& str) const override; - virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit, - const V3Number& width) override { - out.opSel(from, bit.toUInt() + width.toUInt() - 1, bit.toUInt()); - } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { - return widthp()->isOne() ? "VL_BITSEL_%nq%lq%rq%tq(%lw, %P, %li, %ri)" - : isWide() ? "VL_SEL_%nq%lq%rq%tq(%nw,%lw, %P, %li, %ri, %ti)" - : "VL_SEL_%nq%lq%rq%tq(%lw, %P, %li, %ri, %ti)"; - } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool cleanThs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool sizeMattersThs() const override { return false; } - virtual bool same(const AstNode*) const override { return true; } - virtual int instrCount() const override { - return widthInstrs() * (VN_CAST(lsbp(), Const) ? 3 : 10); - } - AstNode* fromp() const { - return op1p(); - } // op1 = Extracting what (nullptr=TBD during parsing) - AstNode* lsbp() const { return op2p(); } // op2 = Msb selection expression - AstNode* widthp() const { return op3p(); } // op3 = Width - int widthConst() const { return VN_AS(widthp(), Const)->toSInt(); } - int lsbConst() const { return VN_AS(lsbp(), Const)->toSInt(); } - int msbConst() const { return lsbConst() + widthConst() - 1; } - VNumRange& declRange() { return m_declRange; } - const VNumRange& declRange() const { return m_declRange; } - void declRange(const VNumRange& flag) { m_declRange = flag; } - int declElWidth() const { return m_declElWidth; } - void declElWidth(int flag) { m_declElWidth = flag; } -}; - -class AstSliceSel final : public AstNodeTriop { - // Multiple array element extraction - // Parents: math|stmt - // Children: varref|arraysel, math, constant math -private: - VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid -public: - AstSliceSel(FileLine* fl, AstNode* fromp, const VNumRange& declRange) - : ASTGEN_SUPER_SliceSel(fl, fromp, new AstConst(fl, declRange.lo()), - new AstConst(fl, declRange.elements())) - , m_declRange{declRange} {} - ASTNODE_NODE_FUNCS(SliceSel) - virtual void dump(std::ostream& str) const override; - virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& lo, - const V3Number& width) override { - V3ERROR_NA; - } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } // Removed before EmitC - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return true; } - virtual bool cleanThs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool sizeMattersThs() const override { return false; } - virtual bool same(const AstNode*) const override { return true; } - virtual int instrCount() const override { return 10; } // Removed before matters - AstNode* fromp() const { - return op1p(); - } // op1 = Extracting what (nullptr=TBD during parsing) - // For widthConst()/loConst etc, see declRange().elements() and other VNumRange methods - VNumRange& declRange() { return m_declRange; } - const VNumRange& declRange() const { return m_declRange; } - void declRange(const VNumRange& flag) { m_declRange = flag; } -}; - -class AstMethodCall final : public AstNodeFTaskRef { - // A reference to a member task (or function) - // PARENTS: stmt/math - // Not all calls are statments vs math. AstNodeStmt needs isStatement() to deal. - // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it -public: - AstMethodCall(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name, - AstNode* pinsp) - : ASTGEN_SUPER_MethodCall(fl, false, name, pinsp) { - setOp2p(fromp); - dtypep(nullptr); // V3Width will resolve - } - AstMethodCall(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp) - : ASTGEN_SUPER_MethodCall(fl, false, name, pinsp) { - setOp2p(fromp); - } - ASTNODE_NODE_FUNCS(MethodCall) - virtual const char* broken() const override { - BROKEN_BASE_RTN(AstNodeFTaskRef::broken()); - BROKEN_RTN(!fromp()); - return nullptr; - } - virtual void dump(std::ostream& str) const override; - virtual bool hasDType() const override { return true; } - void makeStatement() { - statement(true); - dtypeSetVoid(); - } - AstNode* fromp() const { - return op2p(); - } // op2 = Extracting what (nullptr=TBD during parsing) - void fromp(AstNode* nodep) { setOp2p(nodep); } -}; - -class AstCMethodHard final : public AstNodeStmt { - // A reference to a "C" hardcoded member task (or function) - // PARENTS: stmt/math - // Not all calls are statments vs math. AstNodeStmt needs isStatement() to deal. -private: - string m_name; // Name of method - bool m_pure = false; // Pure optimizable -public: - AstCMethodHard(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name, - AstNode* pinsp = nullptr) - : ASTGEN_SUPER_CMethodHard(fl, false) - , m_name{name} { - setOp1p(fromp); - dtypep(nullptr); // V3Width will resolve - addNOp2p(pinsp); - } - AstCMethodHard(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp = nullptr) - : ASTGEN_SUPER_CMethodHard(fl, false) - , m_name{name} { - setOp1p(fromp); - addNOp2p(pinsp); - } - ASTNODE_NODE_FUNCS(CMethodHard) - virtual string name() const override { return m_name; } // * = Var name - virtual bool hasDType() const override { return true; } - virtual void name(const string& name) override { m_name = name; } - virtual bool same(const AstNode* samep) const override { - const AstCMethodHard* asamep = static_cast(samep); - return (m_name == asamep->m_name); - } - virtual bool isPure() const override { return m_pure; } - void pure(bool flag) { m_pure = flag; } - void makeStatement() { - statement(true); - dtypeSetVoid(); - } - AstNode* fromp() const { - return op1p(); - } // op1 = Extracting what (nullptr=TBD during parsing) - void fromp(AstNode* nodep) { setOp1p(nodep); } - AstNode* pinsp() const { return op2p(); } // op2 = Pin interconnection list - void addPinsp(AstNode* nodep) { addOp2p(nodep); } -}; - -class AstVar final : public AstNode { - // A variable (in/out/wire/reg/param) inside a module -private: - string m_name; // Name of variable - string m_origName; // Original name before dot addition - string m_tag; // Holds the string of the verilator tag -- used in XML output. - VVarType m_varType; // Type of variable - VDirection m_direction; // Direction input/output etc - VDirection m_declDirection; // Declared direction input/output etc - VBasicDTypeKwd m_declKwd; // Keyword at declaration time - VLifetime m_lifetime; // Lifetime - VVarAttrClocker m_attrClocker; - MTaskIdSet m_mtaskIds; // MTaskID's that read or write this var - int m_pinNum = 0; // For XML, if non-zero the connection pin number - bool m_ansi : 1; // ANSI port list variable (for dedup check) - bool m_declTyped : 1; // Declared as type (for dedup check) - bool m_tristate : 1; // Inout or triwire or trireg - bool m_primaryIO : 1; // In/out to top level (or directly assigned from same) - bool m_sc : 1; // SystemC variable - bool m_scClocked : 1; // SystemC sc_clk<> needed - bool m_scSensitive : 1; // SystemC sensitive() needed - bool m_sigPublic : 1; // User C code accesses this signal or is top signal - bool m_sigModPublic : 1; // User C code accesses this signal and module - bool m_sigUserRdPublic : 1; // User C code accesses this signal, read only - bool m_sigUserRWPublic : 1; // User C code accesses this signal, read-write - bool m_usedClock : 1; // Signal used as a clock - bool m_usedParam : 1; // Parameter is referenced (on link; later signals not setup) - bool m_usedLoopIdx : 1; // Variable subject of for unrolling - bool m_funcLocal : 1; // Local variable for a function - bool m_funcReturn : 1; // Return variable for a function - bool m_attrClockEn : 1; // User clock enable attribute - bool m_attrScBv : 1; // User force bit vector attribute - bool m_attrIsolateAssign : 1; // User isolate_assignments attribute - bool m_attrSFormat : 1; // User sformat attribute - bool m_attrSplitVar : 1; // declared with split_var metacomment - bool m_fileDescr : 1; // File descriptor - bool m_isRand : 1; // Random variable - bool m_isConst : 1; // Table contains constant data - bool m_isContinuously : 1; // Ever assigned continuously (for force/release) - bool m_isStatic : 1; // Static C variable (for Verilog see instead isAutomatic) - bool m_isPulldown : 1; // Tri0 - bool m_isPullup : 1; // Tri1 - bool m_isIfaceParent : 1; // dtype is reference to interface present in this module - bool m_isDpiOpenArray : 1; // DPI import open array - bool m_isHideLocal : 1; // Verilog local - bool m_isHideProtected : 1; // Verilog protected - bool m_noReset : 1; // Do not do automated reset/randomization - bool m_noSubst : 1; // Do not substitute out references - bool m_overridenParam : 1; // Overridden parameter by #(...) or defparam - bool m_trace : 1; // Trace this variable - bool m_isLatched : 1; // Not assigned in all control paths of combo always - bool m_isForceable : 1; // May be forced/released externally from user C code - - void init() { - m_ansi = false; - m_declTyped = false; - m_tristate = false; - m_primaryIO = false; - m_sc = false; - m_scClocked = false; - m_scSensitive = false; - m_usedClock = false; - m_usedParam = false; - m_usedLoopIdx = false; - m_sigPublic = false; - m_sigModPublic = false; - m_sigUserRdPublic = false; - m_sigUserRWPublic = false; - m_funcLocal = false; - m_funcReturn = false; - m_attrClockEn = false; - m_attrScBv = false; - m_attrIsolateAssign = false; - m_attrSFormat = false; - m_attrSplitVar = false; - m_fileDescr = false; - m_isRand = false; - m_isConst = false; - m_isContinuously = false; - m_isStatic = false; - m_isPulldown = false; - m_isPullup = false; - m_isIfaceParent = false; - m_isDpiOpenArray = false; - m_isHideLocal = false; - m_isHideProtected = false; - m_noReset = false; - m_noSubst = false; - m_overridenParam = false; - m_trace = false; - m_isLatched = false; - m_isForceable = false; - m_attrClocker = VVarAttrClocker::CLOCKER_UNKNOWN; - } - -public: - AstVar(FileLine* fl, VVarType type, const string& name, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER_Var(fl) - , m_name{name} - , m_origName{name} { - init(); - combineType(type); - childDTypep(dtp); // Only for parser - dtypep(nullptr); // V3Width will resolve - if (dtp->basicp()) { - m_declKwd = dtp->basicp()->keyword(); - } else { - m_declKwd = VBasicDTypeKwd::LOGIC; - } - } - AstVar(FileLine* fl, VVarType type, const string& name, AstNodeDType* dtp) - : ASTGEN_SUPER_Var(fl) - , m_name{name} - , m_origName{name} { - init(); - combineType(type); - UASSERT(dtp, "AstVar created with no dtype"); - dtypep(dtp); - if (dtp->basicp()) { - m_declKwd = dtp->basicp()->keyword(); - } else { - m_declKwd = VBasicDTypeKwd::LOGIC; - } - } - AstVar(FileLine* fl, VVarType type, const string& name, VFlagLogicPacked, int wantwidth) - : ASTGEN_SUPER_Var(fl) - , m_name{name} - , m_origName{name} { - init(); - combineType(type); - dtypeSetLogicSized(wantwidth, VSigning::UNSIGNED); - m_declKwd = VBasicDTypeKwd::LOGIC; - } - AstVar(FileLine* fl, VVarType type, const string& name, VFlagBitPacked, int wantwidth) - : ASTGEN_SUPER_Var(fl) - , m_name{name} - , m_origName{name} { - init(); - combineType(type); - dtypeSetBitSized(wantwidth, VSigning::UNSIGNED); - m_declKwd = VBasicDTypeKwd::BIT; - } - AstVar(FileLine* fl, VVarType type, const string& name, AstVar* examplep) - : ASTGEN_SUPER_Var(fl) - , m_name{name} - , m_origName{name} { - init(); - combineType(type); - if (examplep->childDTypep()) childDTypep(examplep->childDTypep()->cloneTree(true)); - dtypeFrom(examplep); - m_declKwd = examplep->declKwd(); - } - ASTNODE_NODE_FUNCS(Var) - virtual void dump(std::ostream& str) const override; - virtual string name() const override { return m_name; } // * = Var name - virtual bool hasDType() const override { return true; } - virtual bool maybePointedTo() const override { return true; } - virtual string origName() const override { return m_origName; } // * = Original name - void origName(const string& name) { m_origName = name; } - VVarType varType() const { return m_varType; } // * = Type of variable - void direction(const VDirection& flag) { - m_direction = flag; - if (m_direction == VDirection::INOUT) m_tristate = true; - } - VDirection direction() const { return m_direction; } - bool isIO() const { return m_direction != VDirection::NONE; } - void declDirection(const VDirection& flag) { m_declDirection = flag; } - VDirection declDirection() const { return m_declDirection; } - void varType(VVarType type) { m_varType = type; } - void varType2Out() { - m_tristate = false; - m_direction = VDirection::OUTPUT; - } - void varType2In() { - m_tristate = false; - m_direction = VDirection::INPUT; - } - VBasicDTypeKwd declKwd() const { return m_declKwd; } - string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv - // Return C /*public*/ type for argument: bool, uint32_t, uint64_t, etc. - string cPubArgType(bool named, bool forReturn) const; - string dpiArgType(bool named, bool forReturn) const; // Return DPI-C type for argument - string dpiTmpVarType(const string& varName) const; - // Return Verilator internal type for argument: CData, SData, IData, WData - string vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc = "", - bool asRef = false) const; - string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc - string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc - string vlPropDecl(const string& propName) const; // Return VerilatorVarProps declaration - void combineType(VVarType type); - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - // op1 = Range of variable - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - // op2 = Net delay - AstNode* delayp() const { return op2p(); } - void delayp(AstNode* const nodep) { setNOp2p(nodep); } - AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } - // (Slow) recurse down to find basic data type (Note don't need virtual - - // AstVar isn't a NodeDType) - AstBasicDType* basicp() const { return subDTypep()->basicp(); } - // op3 = Initial value that never changes (static const), or constructor argument for - // MTASKSTATE variables - AstNode* valuep() const { return op3p(); } - // It's valuep(), not constp(), as may be more complicated than an AstConst - void valuep(AstNode* nodep) { setOp3p(nodep); } - void addAttrsp(AstNode* nodep) { addNOp4p(nodep); } - AstNode* attrsp() const { return op4p(); } // op4 = Attributes during early parse - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } - void ansi(bool flag) { m_ansi = flag; } - void declTyped(bool flag) { m_declTyped = flag; } - void attrClockEn(bool flag) { m_attrClockEn = flag; } - void attrClocker(VVarAttrClocker flag) { m_attrClocker = flag; } - void attrFileDescr(bool flag) { m_fileDescr = flag; } - void attrScClocked(bool flag) { m_scClocked = flag; } - void attrScBv(bool flag) { m_attrScBv = flag; } - void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; } - void attrSFormat(bool flag) { m_attrSFormat = flag; } - void attrSplitVar(bool flag) { m_attrSplitVar = flag; } - void usedClock(bool flag) { m_usedClock = flag; } - void usedParam(bool flag) { m_usedParam = flag; } - void usedLoopIdx(bool flag) { m_usedLoopIdx = flag; } - void sigPublic(bool flag) { m_sigPublic = flag; } - void sigModPublic(bool flag) { m_sigModPublic = flag; } - void sigUserRdPublic(bool flag) { - m_sigUserRdPublic = flag; - if (flag) sigPublic(true); - } - void sigUserRWPublic(bool flag) { - m_sigUserRWPublic = flag; - if (flag) sigUserRdPublic(true); - } - void sc(bool flag) { m_sc = flag; } - void scSensitive(bool flag) { m_scSensitive = flag; } - void primaryIO(bool flag) { m_primaryIO = flag; } - void isRand(bool flag) { m_isRand = flag; } - void isConst(bool flag) { m_isConst = flag; } - void isContinuously(bool flag) { m_isContinuously = flag; } - void isStatic(bool flag) { m_isStatic = flag; } - void isIfaceParent(bool flag) { m_isIfaceParent = flag; } - void funcLocal(bool flag) { m_funcLocal = flag; } - void funcReturn(bool flag) { m_funcReturn = flag; } - void isDpiOpenArray(bool flag) { m_isDpiOpenArray = flag; } - bool isDpiOpenArray() const { return m_isDpiOpenArray; } - bool isHideLocal() const { return m_isHideLocal; } - void isHideLocal(bool flag) { m_isHideLocal = flag; } - bool isHideProtected() const { return m_isHideProtected; } - void isHideProtected(bool flag) { m_isHideProtected = flag; } - void noReset(bool flag) { m_noReset = flag; } - bool noReset() const { return m_noReset; } - void noSubst(bool flag) { m_noSubst = flag; } - bool noSubst() const { return m_noSubst; } - void overriddenParam(bool flag) { m_overridenParam = flag; } - bool overriddenParam() const { return m_overridenParam; } - void trace(bool flag) { m_trace = flag; } - void isLatched(bool flag) { m_isLatched = flag; } - bool isForceable() const { return m_isForceable; } - void setForceable() { m_isForceable = true; } - // METHODS - virtual void name(const string& name) override { m_name = name; } - virtual void tag(const string& text) override { m_tag = text; } - virtual string tag() const override { return m_tag; } - bool isAnsi() const { return m_ansi; } - bool isContinuously() const { return m_isContinuously; } - bool isDeclTyped() const { return m_declTyped; } - bool isInoutish() const { return m_direction.isInoutish(); } - bool isNonOutput() const { return m_direction.isNonOutput(); } - bool isReadOnly() const { return m_direction.isReadOnly(); } - bool isWritable() const { return m_direction.isWritable(); } - bool isTristate() const { return m_tristate; } - bool isPrimaryIO() const { return m_primaryIO; } - bool isPrimaryInish() const { return isPrimaryIO() && isNonOutput(); } - bool isIfaceRef() const { return (varType() == VVarType::IFACEREF); } - bool isIfaceParent() const { return m_isIfaceParent; } - bool isSignal() const { return varType().isSignal(); } - bool isTemp() const { return varType().isTemp(); } - bool isToggleCoverable() const { - return ((isIO() || isSignal()) - && (isIO() || isBitLogic()) - // Wrapper would otherwise duplicate wrapped module's coverage - && !isSc() && !isPrimaryIO() && !isConst() && !isDouble() && !isString()); - } - bool isClassMember() const { return varType() == VVarType::MEMBER; } - bool isStatementTemp() const { return (varType() == VVarType::STMTTEMP); } - bool isXTemp() const { return (varType() == VVarType::XTEMP); } - bool isParam() const { - return (varType() == VVarType::LPARAM || varType() == VVarType::GPARAM); - } - bool isGParam() const { return (varType() == VVarType::GPARAM); } - bool isGenVar() const { return (varType() == VVarType::GENVAR); } - bool isBitLogic() const { - AstBasicDType* bdtypep = basicp(); - return bdtypep && bdtypep->isBitLogic(); - } - bool isUsedClock() const { return m_usedClock; } - bool isUsedParam() const { return m_usedParam; } - bool isUsedLoopIdx() const { return m_usedLoopIdx; } - bool isSc() const { return m_sc; } - bool isScQuad() const; - bool isScBv() const; - bool isScUint() const; - bool isScBigUint() const; - bool isScSensitive() const { return m_scSensitive; } - bool isSigPublic() const; - bool isSigModPublic() const { return m_sigModPublic; } - bool isSigUserRdPublic() const { return m_sigUserRdPublic; } - bool isSigUserRWPublic() const { return m_sigUserRWPublic; } - bool isTrace() const { return m_trace; } - bool isRand() const { return m_isRand; } - bool isConst() const { return m_isConst; } - bool isStatic() const { return m_isStatic; } - bool isLatched() const { return m_isLatched; } - bool isFuncLocal() const { return m_funcLocal; } - bool isFuncReturn() const { return m_funcReturn; } - bool isPullup() const { return m_isPullup; } - bool isPulldown() const { return m_isPulldown; } - bool attrClockEn() const { return m_attrClockEn; } - bool attrScBv() const { return m_attrScBv; } - bool attrFileDescr() const { return m_fileDescr; } - bool attrScClocked() const { return m_scClocked; } - bool attrSFormat() const { return m_attrSFormat; } - bool attrSplitVar() const { return m_attrSplitVar; } - bool attrIsolateAssign() const { return m_attrIsolateAssign; } - VVarAttrClocker attrClocker() const { return m_attrClocker; } - virtual string verilogKwd() const override; - void lifetime(const VLifetime& flag) { m_lifetime = flag; } - VLifetime lifetime() const { return m_lifetime; } - void propagateAttrFrom(AstVar* fromp) { - // This is getting connected to fromp; keep attributes - // Note the method below too - if (fromp->attrClockEn()) attrClockEn(true); - if (fromp->attrFileDescr()) attrFileDescr(true); - if (fromp->attrIsolateAssign()) attrIsolateAssign(true); - if (fromp->isContinuously()) isContinuously(true); - } - bool gateMultiInputOptimizable() const { - // Ok to gate optimize; must return false if propagateAttrFrom would do anything - return (!attrClockEn() && !isUsedClock()); - } - void combineType(AstVar* typevarp) { - // This is same as typevarp (for combining input & reg decls) - // "this" is the input var. typevarp is the reg var. - propagateAttrFrom(typevarp); - combineType(typevarp->varType()); - if (typevarp->isSigPublic()) sigPublic(true); - if (typevarp->isSigModPublic()) sigModPublic(true); - if (typevarp->isSigUserRdPublic()) sigUserRdPublic(true); - if (typevarp->isSigUserRWPublic()) sigUserRWPublic(true); - if (typevarp->attrScClocked()) attrScClocked(true); - } - void inlineAttrReset(const string& name) { - if (direction() == VDirection::INOUT && varType() == VVarType::WIRE) { - m_varType = VVarType::TRIWIRE; - } - m_direction = VDirection::NONE; - m_name = name; - } - static AstVar* scVarRecurse(AstNode* nodep); - void addProducingMTaskId(int id) { m_mtaskIds.insert(id); } - void addConsumingMTaskId(int id) { m_mtaskIds.insert(id); } - const MTaskIdSet& mtaskIds() const { return m_mtaskIds; } - void pinNum(int id) { m_pinNum = id; } - int pinNum() const { return m_pinNum; } -}; - -class AstDefParam final : public AstNode { - // A defparam assignment - // Parents: MODULE - // Children: math -private: - string m_name; // Name of variable getting set - string m_path; // Dotted cellname to set parameter of -public: - AstDefParam(FileLine* fl, const string& path, const string& name, AstNode* rhsp) - : ASTGEN_SUPER_DefParam(fl) { - setOp1p(rhsp); - m_name = name; - m_path = path; - } - virtual string name() const override { return m_name; } // * = Scope name - ASTNODE_NODE_FUNCS(DefParam) - virtual bool same(const AstNode*) const override { return true; } - AstNode* rhsp() const { return op1p(); } // op1 = Assign from - string path() const { return m_path; } -}; - -class AstImplicit final : public AstNode { - // Create implicit wires and do nothing else, for gates that are ignored - // Parents: MODULE -public: - AstImplicit(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER_Implicit(fl) { - addNOp1p(exprsp); - } - ASTNODE_NODE_FUNCS(Implicit) - AstNode* exprsp() const { return op1p(); } // op1 = Assign from -}; - -class AstScope final : public AstNode { - // A particular usage of a cell - // Parents: MODULE - // Children: NODEBLOCK -private: - // An AstScope->name() is special: . indicates an uninlined scope, __DOT__ an inlined scope - string m_name; // Name - AstScope* const m_aboveScopep; // Scope above this one in the hierarchy (nullptr if top) - AstCell* const m_aboveCellp; // Cell above this in the hierarchy (nullptr if top) - AstNodeModule* const m_modp; // Module scope corresponds to -public: - AstScope(FileLine* fl, AstNodeModule* modp, const string& name, AstScope* aboveScopep, - AstCell* aboveCellp) - : ASTGEN_SUPER_Scope(fl) - , m_name{name} - , m_aboveScopep{aboveScopep} - , m_aboveCellp{aboveCellp} - , m_modp{modp} {} - ASTNODE_NODE_FUNCS(Scope) - virtual void cloneRelink() override; - virtual const char* broken() const override; - virtual bool maybePointedTo() const override { return true; } - virtual string name() const override { return m_name; } // * = Scope name - virtual void name(const string& name) override { m_name = name; } - virtual void dump(std::ostream& str) const override; - string nameDotless() const; - string nameVlSym() const { return ((string("vlSymsp->")) + nameDotless()); } - AstNodeModule* modp() const { return m_modp; } - void addVarp(AstVarScope* nodep) { addOp1p((AstNode*)nodep); } - AstVarScope* varsp() const { return VN_AS(op1p(), VarScope); } // op1 = AstVarScope's - void addActivep(AstNode* nodep) { addOp2p(nodep); } - AstNode* blocksp() const { return op2p(); } // op2 = Block names - void addFinalClkp(AstNode* nodep) { addOp3p(nodep); } - AstNode* finalClksp() const { return op3p(); } // op3 = Final assigns for clock correction - AstScope* aboveScopep() const { return m_aboveScopep; } - AstCell* aboveCellp() const { return m_aboveCellp; } - bool isTop() const { return aboveScopep() == nullptr; } // At top of hierarchy -}; - -class AstTopScope final : public AstNode { - // A singleton, held under the top level AstModule. Holds the top level AstScope, - // and after V3ActiveTop, the global list of AstSenTrees (list of unique sensitivity lists). - // Parent: Top level AstModule - // Children: AstSenTree, AstScope - friend class AstNetlist; // Only the AstNetlist can create one - AstTopScope(FileLine* fl, AstScope* ascopep) - : ASTGEN_SUPER_TopScope(fl) { - addOp2p(ascopep); - } - -public: - ASTNODE_NODE_FUNCS(TopScope) - virtual bool maybePointedTo() const override { return true; } - AstSenTree* senTreesp() const { return VN_AS(op1p(), SenTree); } - void addSenTreep(AstSenTree* nodep) { addOp1p((AstNode*)nodep); } - AstScope* scopep() const { return VN_AS(op2p(), Scope); } -}; - -class AstVarScope final : public AstNode { - // A particular scoped usage of a variable - // That is, as a module is used under multiple cells, we get a different - // varscope for each var in the module - // Parents: MODULE - // Children: none -private: - AstScope* m_scopep; // Scope variable is underneath - AstVar* m_varp; // [AfterLink] Pointer to variable itself - bool m_circular : 1; // Used in circular ordering dependency, need change detect - bool m_trace : 1; // Tracing is turned on for this scope -public: - AstVarScope(FileLine* fl, AstScope* scopep, AstVar* varp) - : ASTGEN_SUPER_VarScope(fl) - , m_scopep{scopep} - , m_varp{varp} { - UASSERT_OBJ(scopep, fl, "Scope must be non-null"); - UASSERT_OBJ(varp, fl, "Var must be non-null"); - m_circular = false; - m_trace = true; - dtypeFrom(varp); - } - ASTNODE_NODE_FUNCS(VarScope) - virtual void cloneRelink() override { - if (m_varp && m_varp->clonep()) { - m_varp = m_varp->clonep(); - UASSERT(m_scopep->clonep(), "No clone cross link: " << this); - m_scopep = m_scopep->clonep(); - } - } - virtual const char* broken() const override { - BROKEN_RTN(m_varp && !m_varp->brokeExists()); - BROKEN_RTN(m_scopep && !m_scopep->brokeExists()); - return nullptr; - } - virtual bool maybePointedTo() const override { return true; } - virtual string name() const override { return scopep()->name() + "->" + varp()->name(); } - virtual void dump(std::ostream& str) const override; - virtual bool hasDType() const override { return true; } - AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable - AstScope* scopep() const { return m_scopep; } // Pointer to scope it's under - void scopep(AstScope* nodep) { m_scopep = nodep; } - // op1 = Calculation of value of variable, nullptr=complicated - AstNode* valuep() const { return op1p(); } - void valuep(AstNode* valuep) { addOp1p(valuep); } - bool isCircular() const { return m_circular; } - void circular(bool flag) { m_circular = flag; } - bool isTrace() const { return m_trace; } - void trace(bool flag) { m_trace = flag; } -}; - -class AstVarRef final : public AstNodeVarRef { - // A reference to a variable (lvalue or rvalue) -public: - AstVarRef(FileLine* fl, const string& name, const VAccess& access) - : ASTGEN_SUPER_VarRef(fl, name, nullptr, access) {} - // This form only allowed post-link because output/wire compression may - // lead to deletion of AstVar's - AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access) - : ASTGEN_SUPER_VarRef(fl, varp->name(), varp, access) {} - // This form only allowed post-link (see above) - AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access) - : ASTGEN_SUPER_VarRef(fl, varscp->varp()->name(), varscp->varp(), access) { - varScopep(varscp); - } - ASTNODE_NODE_FUNCS(VarRef) - virtual void dump(std::ostream& str) const override; - virtual bool same(const AstNode* samep) const override { - return same(static_cast(samep)); - } - inline bool same(const AstVarRef* samep) const { - if (varScopep()) { - return (varScopep() == samep->varScopep() && access() == samep->access()); - } else { - return (selfPointer() == samep->selfPointer() - && varp()->name() == samep->varp()->name() && access() == samep->access()); - } - } - inline bool sameNoLvalue(AstVarRef* samep) const { - if (varScopep()) { - return (varScopep() == samep->varScopep()); - } else { - return (selfPointer() == samep->selfPointer() - && (!selfPointer().empty() || !samep->selfPointer().empty()) - && varp()->name() == samep->varp()->name()); - } - } - virtual int instrCount() const override { - return widthInstrs() * (access().isReadOrRW() ? INSTR_COUNT_LD : 1); - } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } -}; - -class AstVarXRef final : public AstNodeVarRef { - // A VarRef to something in another module before AstScope. - // Includes pin on a cell, as part of a ASSIGN statement to connect I/Os until AstScope -private: - string m_dotted; // Dotted part of scope the name()'ed reference is under or "" - string m_inlinedDots; // Dotted hierarchy flattened out -public: - AstVarXRef(FileLine* fl, const string& name, const string& dotted, const VAccess& access) - : ASTGEN_SUPER_VarXRef(fl, name, nullptr, access) - , m_dotted{dotted} {} - AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const VAccess& access) - : ASTGEN_SUPER_VarXRef(fl, varp->name(), varp, access) - , m_dotted{dotted} { - dtypeFrom(varp); - } - ASTNODE_NODE_FUNCS(VarXRef) - virtual void dump(std::ostream& str) const override; - string dotted() const { return m_dotted; } - void dotted(const string& dotted) { m_dotted = dotted; } - string inlinedDots() const { return m_inlinedDots; } - void inlinedDots(const string& flag) { m_inlinedDots = flag; } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } - virtual bool same(const AstNode* samep) const override { - const AstVarXRef* asamep = static_cast(samep); - return (selfPointer() == asamep->selfPointer() && varp() == asamep->varp() - && name() == asamep->name() && dotted() == asamep->dotted()); - } -}; - -class AstAddrOfCFunc final : public AstNodeMath { - // Get address of CFunc -private: - AstCFunc* m_funcp; // Pointer to function itself - -public: - AstAddrOfCFunc(FileLine* fl, AstCFunc* funcp) - : ASTGEN_SUPER_AddrOfCFunc(fl) - , m_funcp{funcp} { - dtypep(findCHandleDType()); - } - -public: - ASTNODE_NODE_FUNCS(AddrOfCFunc) - virtual void cloneRelink() override; - virtual const char* broken() const override; - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - AstCFunc* funcp() const { return m_funcp; } -}; - -class AstPin final : public AstNode { - // A pin on a cell -private: - int m_pinNum; // Pin number - string m_name; // Pin name, or "" for number based interconnect - AstVar* m_modVarp = nullptr; // Input/output this pin connects to on submodule. - AstParamTypeDType* m_modPTypep = nullptr; // Param type this pin connects to on submodule. - bool m_param = false; // Pin connects to parameter - bool m_svImplicit = false; // Pin is SystemVerilog .name'ed -public: - AstPin(FileLine* fl, int pinNum, const string& name, AstNode* exprp) - : ASTGEN_SUPER_Pin(fl) - , m_pinNum{pinNum} - , m_name{name} { - setNOp1p(exprp); - } - AstPin(FileLine* fl, int pinNum, AstVarRef* varname, AstNode* exprp) - : ASTGEN_SUPER_Pin(fl) - , m_pinNum{pinNum} - , m_name{varname->name()} { - setNOp1p(exprp); - } - ASTNODE_NODE_FUNCS(Pin) - virtual void dump(std::ostream& str) const override; - virtual const char* broken() const override { - BROKEN_RTN(m_modVarp && !m_modVarp->brokeExists()); - BROKEN_RTN(m_modPTypep && !m_modPTypep->brokeExists()); - return nullptr; - } - virtual string name() const override { return m_name; } // * = Pin name, ""=go by number - virtual void name(const string& name) override { m_name = name; } - virtual string prettyOperatorName() const override { - return modVarp() - ? ((modVarp()->direction().isAny() ? modVarp()->direction().prettyName() + " " - : "") - + "port connection " + modVarp()->prettyNameQ()) - : "port connection"; - } - bool dotStar() const { return name() == ".*"; } // Fake name for .* connections until linked - int pinNum() const { return m_pinNum; } - void exprp(AstNode* nodep) { addOp1p(nodep); } - // op1 = Expression connected to pin, nullptr if unconnected - AstNode* exprp() const { return op1p(); } - AstVar* modVarp() const { return m_modVarp; } // [After Link] Pointer to variable - void modVarp(AstVar* nodep) { m_modVarp = nodep; } - // [After Link] Pointer to variable - AstParamTypeDType* modPTypep() const { return m_modPTypep; } - void modPTypep(AstParamTypeDType* nodep) { m_modPTypep = nodep; } - bool param() const { return m_param; } - void param(bool flag) { m_param = flag; } - bool svImplicit() const { return m_svImplicit; } - void svImplicit(bool flag) { m_svImplicit = flag; } -}; - -class AstArg final : public AstNode { - // An argument to a function/task -private: - string m_name; // Pin name, or "" for number based interconnect -public: - AstArg(FileLine* fl, const string& name, AstNode* exprp) - : ASTGEN_SUPER_Arg(fl) - , m_name{name} { - setNOp1p(exprp); - } - ASTNODE_NODE_FUNCS(Arg) - virtual string name() const override { return m_name; } // * = Pin name, ""=go by number - virtual void name(const string& name) override { m_name = name; } - void exprp(AstNode* nodep) { addOp1p(nodep); } - // op1 = Expression connected to pin, nullptr if unconnected - AstNode* exprp() const { return op1p(); } - bool emptyConnectNoNext() const { return !exprp() && name() == "" && !nextp(); } -}; - -class AstModule final : public AstNodeModule { - // A module declaration -private: - const bool m_isProgram; // Module represents a program -public: - AstModule(FileLine* fl, const string& name, bool program = false) - : ASTGEN_SUPER_Module(fl, name) - , m_isProgram{program} {} - ASTNODE_NODE_FUNCS(Module) - virtual string verilogKwd() const override { return m_isProgram ? "program" : "module"; } - virtual bool timescaleMatters() const override { return true; } -}; - -class AstNotFoundModule final : public AstNodeModule { - // A missing module declaration -public: - AstNotFoundModule(FileLine* fl, const string& name) - : ASTGEN_SUPER_NotFoundModule(fl, name) {} - ASTNODE_NODE_FUNCS(NotFoundModule) - virtual string verilogKwd() const override { return "/*not-found-*/ module"; } - virtual bool timescaleMatters() const override { return false; } -}; - -class AstPackage final : public AstNodeModule { - // A package declaration -public: - AstPackage(FileLine* fl, const string& name) - : ASTGEN_SUPER_Package(fl, name) {} - ASTNODE_NODE_FUNCS(Package) - virtual string verilogKwd() const override { return "package"; } - virtual bool timescaleMatters() const override { return !isDollarUnit(); } - static string dollarUnitName() { return AstNode::encodeName("$unit"); } - bool isDollarUnit() const { return name() == dollarUnitName(); } -}; - -class AstPrimitive final : public AstNodeModule { - // A primitive declaration -public: - AstPrimitive(FileLine* fl, const string& name) - : ASTGEN_SUPER_Primitive(fl, name) {} - ASTNODE_NODE_FUNCS(Primitive) - virtual string verilogKwd() const override { return "primitive"; } - virtual bool timescaleMatters() const override { return false; } -}; - -class AstPackageExportStarStar final : public AstNode { - // A package export *::* declaration -public: - // cppcheck-suppress noExplicitConstructor - AstPackageExportStarStar(FileLine* fl) - : ASTGEN_SUPER_PackageExportStarStar(fl) {} - ASTNODE_NODE_FUNCS(PackageExportStarStar) -}; - -class AstPackageExport final : public AstNode { -private: - // A package export declaration - string m_name; - AstPackage* m_packagep; // Package hierarchy -public: - AstPackageExport(FileLine* fl, AstPackage* packagep, const string& name) - : ASTGEN_SUPER_PackageExport(fl) - , m_name{name} - , m_packagep{packagep} {} - ASTNODE_NODE_FUNCS(PackageExport) - virtual const char* broken() const override { - BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { - if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep(); - } - virtual void dump(std::ostream& str) const override; - virtual string name() const override { return m_name; } - AstPackage* packagep() const { return m_packagep; } - void packagep(AstPackage* nodep) { m_packagep = nodep; } -}; - -class AstPackageImport final : public AstNode { -private: - // A package import declaration - string m_name; - AstPackage* m_packagep; // Package hierarchy -public: - AstPackageImport(FileLine* fl, AstPackage* packagep, const string& name) - : ASTGEN_SUPER_PackageImport(fl) - , m_name{name} - , m_packagep{packagep} {} - ASTNODE_NODE_FUNCS(PackageImport) - virtual const char* broken() const override { - BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { - if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep(); - } - virtual void dump(std::ostream& str) const override; - virtual string name() const override { return m_name; } - AstPackage* packagep() const { return m_packagep; } - void packagep(AstPackage* nodep) { m_packagep = nodep; } -}; - -class AstIface final : public AstNodeModule { - // A module declaration -public: - AstIface(FileLine* fl, const string& name) - : ASTGEN_SUPER_Iface(fl, name) {} - ASTNODE_NODE_FUNCS(Iface) - // Interfaces have `timescale applicability but lots of code seems to - // get false warnings if we enable this - virtual string verilogKwd() const override { return "interface"; } - virtual bool timescaleMatters() const override { return false; } -}; - -class AstMemberSel final : public AstNodeMath { - // Parents: math|stmt - // Children: varref|arraysel, math -private: - // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it - string m_name; - AstVar* m_varp = nullptr; // Post link, variable within class that is target of selection -public: - AstMemberSel(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name) - : ASTGEN_SUPER_MemberSel(fl) - , m_name{name} { - setOp1p(fromp); - dtypep(nullptr); // V3Width will resolve - } - AstMemberSel(FileLine* fl, AstNode* fromp, AstNodeDType* dtp) - : ASTGEN_SUPER_MemberSel(fl) - , m_name{dtp->name()} { - setOp1p(fromp); - dtypep(dtp); - } - ASTNODE_NODE_FUNCS(MemberSel) - virtual void cloneRelink() override { - if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep(); - } - virtual const char* broken() const override { - BROKEN_RTN(m_varp && !m_varp->brokeExists()); - return nullptr; - } - virtual void dump(std::ostream& str) const override; - virtual string name() const override { return m_name; } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } - virtual bool same(const AstNode* samep) const override { - return true; - } // dtype comparison does it - virtual int instrCount() const override { return widthInstrs(); } - AstNode* fromp() const { - return op1p(); - } // op1 = Extracting what (nullptr=TBD during parsing) - void fromp(AstNode* nodep) { setOp1p(nodep); } - AstVar* varp() const { return m_varp; } - void varp(AstVar* nodep) { m_varp = nodep; } -}; - -class AstModportFTaskRef final : public AstNode { - // An import/export referenced under a modport - // The storage for the function itself is inside the - // interface/instantiator, thus this is a reference - // PARENT: AstModport -private: - string m_name; // Name of the variable referenced - bool m_export; // Type of the function (import/export) - AstNodeFTask* m_ftaskp = nullptr; // Link to the function -public: - AstModportFTaskRef(FileLine* fl, const string& name, bool isExport) - : ASTGEN_SUPER_ModportFTaskRef(fl) - , m_name{name} - , m_export{isExport} {} - ASTNODE_NODE_FUNCS(ModportFTaskRef) - virtual const char* broken() const override { - BROKEN_RTN(m_ftaskp && !m_ftaskp->brokeExists()); - return nullptr; - } - virtual void dump(std::ostream& str) const override; - virtual string name() const override { return m_name; } - virtual void cloneRelink() override { - if (m_ftaskp && m_ftaskp->clonep()) m_ftaskp = m_ftaskp->clonep(); - } - bool isImport() const { return !m_export; } - bool isExport() const { return m_export; } - AstNodeFTask* ftaskp() const { return m_ftaskp; } // [After Link] Pointer to variable - void ftaskp(AstNodeFTask* ftaskp) { m_ftaskp = ftaskp; } -}; - -class AstModportVarRef final : public AstNode { - // A input/output/etc variable referenced under a modport - // The storage for the variable itself is inside the interface, thus this is a reference - // PARENT: AstModport -private: - string m_name; // Name of the variable referenced - VDirection m_direction; // Direction of the variable (in/out) - AstVar* m_varp = nullptr; // Link to the actual Var -public: - AstModportVarRef(FileLine* fl, const string& name, VDirection::en direction) - : ASTGEN_SUPER_ModportVarRef(fl) - , m_name{name} - , m_direction{direction} {} - ASTNODE_NODE_FUNCS(ModportVarRef) - virtual const char* broken() const override { - BROKEN_RTN(m_varp && !m_varp->brokeExists()); - return nullptr; - } - virtual void dump(std::ostream& str) const override; - virtual void cloneRelink() override { - if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep(); - } - virtual string name() const override { return m_name; } - void direction(const VDirection& flag) { m_direction = flag; } - VDirection direction() const { return m_direction; } - AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable - void varp(AstVar* varp) { m_varp = varp; } -}; - -class AstModport final : public AstNode { - // A modport in an interface -private: - string m_name; // Name of the modport -public: - AstModport(FileLine* fl, const string& name, AstNode* varsp) - : ASTGEN_SUPER_Modport(fl) - , m_name{name} { - addNOp1p(varsp); - } - virtual string name() const override { return m_name; } - virtual bool maybePointedTo() const override { return true; } - ASTNODE_NODE_FUNCS(Modport) - AstNode* varsp() const { return op1p(); } // op1 = List of Vars -}; - -class AstIntfRef final : public AstNode { - // An interface reference -private: - string m_name; // Name of the reference -public: - AstIntfRef(FileLine* fl, const string& name) - : ASTGEN_SUPER_IntfRef(fl) - , m_name{name} {} - virtual string name() const override { return m_name; } - ASTNODE_NODE_FUNCS(IntfRef) -}; - -class AstCell final : public AstNode { - // A instantiation cell or interface call (don't know which until link) -private: - FileLine* m_modNameFileline; // Where module the cell instances token was - string m_name; // Cell name - string m_origName; // Original name before dot addition - string m_modName; // Module the cell instances - AstNodeModule* m_modp = nullptr; // [AfterLink] Pointer to module instanced - bool m_hasIfaceVar : 1; // True if a Var has been created for this cell - bool m_recursive : 1; // Self-recursive module - bool m_trace : 1; // Trace this cell -public: - AstCell(FileLine* fl, FileLine* mfl, const string& instName, const string& modName, - AstPin* pinsp, AstPin* paramsp, AstRange* rangep) - : ASTGEN_SUPER_Cell(fl) - , m_modNameFileline{mfl} - , m_name{instName} - , m_origName{instName} - , m_modName{modName} - , m_hasIfaceVar{false} - , m_recursive{false} - , m_trace{true} { - addNOp1p(pinsp); - addNOp2p(paramsp); - setNOp3p(rangep); - } - ASTNODE_NODE_FUNCS(Cell) - // No cloneRelink, we presume cloneee's want the same module linkages - virtual void dump(std::ostream& str) const override; - virtual const char* broken() const override { - BROKEN_RTN(m_modp && !m_modp->brokeExists()); - return nullptr; - } - virtual bool maybePointedTo() const override { return true; } - // ACCESSORS - virtual string name() const override { return m_name; } // * = Cell name - virtual void name(const string& name) override { m_name = name; } - virtual string origName() const override { return m_origName; } // * = Original name - void origName(const string& name) { m_origName = name; } - string modName() const { return m_modName; } // * = Instance name - void modName(const string& name) { m_modName = name; } - FileLine* modNameFileline() const { return m_modNameFileline; } - AstPin* pinsp() const { return VN_AS(op1p(), Pin); } // op1 = List of cell ports - // op2 = List of parameter #(##) values - AstPin* paramsp() const { return VN_AS(op2p(), Pin); } - // op3 = Range of arrayed instants (nullptr=not ranged) - AstRange* rangep() const { return VN_AS(op3p(), Range); } - // op4 = List of interface references - AstIntfRef* intfRefp() const { return VN_AS(op4p(), IntfRef); } - AstNodeModule* modp() const { return m_modp; } // [AfterLink] = Pointer to module instantiated - void addPinsp(AstPin* nodep) { addOp1p(nodep); } - void addParamsp(AstPin* nodep) { addOp2p(nodep); } - void addIntfRefp(AstIntfRef* nodep) { addOp4p(nodep); } - void modp(AstNodeModule* nodep) { m_modp = nodep; } - bool hasIfaceVar() const { return m_hasIfaceVar; } - void hasIfaceVar(bool flag) { m_hasIfaceVar = flag; } - void trace(bool flag) { m_trace = flag; } - bool isTrace() const { return m_trace; } - void recursive(bool flag) { m_recursive = flag; } - bool recursive() const { return m_recursive; } -}; - -class AstCellInline final : public AstNode { - // A instantiation cell that was removed by inlining - // For communication between V3Inline and V3LinkDot, - // except for VPI runs where it exists until the end. - // It is augmented with the scope in V3Scope for VPI. - // Children: When 2 levels inlined, other CellInline under this -private: - string m_name; // Cell name, possibly {a}__DOT__{b}... - const string - m_origModName; // Original name of the module, ignoring name() changes, for dot lookup - AstScope* m_scopep = nullptr; // The scope that the cell is inlined into - VTimescale m_timeunit; // Parent module time unit -public: - AstCellInline(FileLine* fl, const string& name, const string& origModName, - const VTimescale& timeunit) - : ASTGEN_SUPER_CellInline(fl) - , m_name{name} - , m_origModName{origModName} - , m_timeunit{timeunit} {} - ASTNODE_NODE_FUNCS(CellInline) - virtual void dump(std::ostream& str) const override; - virtual const char* broken() const override { - BROKEN_RTN(m_scopep && !m_scopep->brokeExists()); - return nullptr; - } - // ACCESSORS - virtual string name() const override { return m_name; } // * = Cell name - string origModName() const { return m_origModName; } // * = modp()->origName() before inlining - virtual void name(const string& name) override { m_name = name; } - void scopep(AstScope* scp) { m_scopep = scp; } - AstScope* scopep() const { return m_scopep; } - void timeunit(const VTimescale& flag) { m_timeunit = flag; } - VTimescale timeunit() const { return m_timeunit; } -}; - -class AstCellRef final : public AstNode { - // As-of-yet unlinkable reference into a cell -private: - string m_name; // Cell name -public: - AstCellRef(FileLine* fl, const string& name, AstNode* cellp, AstNode* exprp) - : ASTGEN_SUPER_CellRef(fl) - , m_name{name} { - addNOp1p(cellp); - addNOp2p(exprp); - } - ASTNODE_NODE_FUNCS(CellRef) - // ACCESSORS - virtual string name() const override { return m_name; } // * = Array name - AstNode* cellp() const { return op1p(); } // op1 = Cell - AstNode* exprp() const { return op2p(); } // op2 = Expression -}; - -class AstCellArrayRef final : public AstNode { - // As-of-yet unlinkable reference into an array of cells -private: - string m_name; // Array name -public: - AstCellArrayRef(FileLine* fl, const string& name, AstNode* selectExprp) - : ASTGEN_SUPER_CellArrayRef(fl) - , m_name{name} { - addNOp1p(selectExprp); - } - ASTNODE_NODE_FUNCS(CellArrayRef) - // ACCESSORS - virtual string name() const override { return m_name; } // * = Array name - AstNode* selp() const { return op1p(); } // op1 = Select expression -}; - -class AstUnlinkedRef final : public AstNode { - // As-of-yet unlinkable Ref -private: - string m_name; // Var name -public: - AstUnlinkedRef(FileLine* fl, AstNode* refp, const string& name, AstNode* crp) - : ASTGEN_SUPER_UnlinkedRef(fl) - , m_name{name} { - addNOp1p(refp); - addNOp2p(crp); - } - ASTNODE_NODE_FUNCS(UnlinkedRef) - // ACCESSORS - virtual string name() const override { return m_name; } // * = Var name - AstNode* refp() const { return op1p(); } // op1 = VarXRef or AstNodeFTaskRef - AstNode* cellrefp() const { return op2p(); } // op2 = CellArrayRef or CellRef -}; - -class AstBind final : public AstNode { - // Parents: MODULE - // Children: CELL -private: - string m_name; // Binding to name -public: - AstBind(FileLine* fl, const string& name, AstNode* cellsp) - : ASTGEN_SUPER_Bind(fl) - , m_name{name} { - UASSERT_OBJ(VN_IS(cellsp, Cell), cellsp, "Only instances allowed to be bound"); - addNOp1p(cellsp); - } - ASTNODE_NODE_FUNCS(Bind) - // ACCESSORS - virtual string name() const override { return m_name; } // * = Bind Target name - virtual void name(const string& name) override { m_name = name; } - AstNode* cellsp() const { return op1p(); } // op1 = cells -}; - -class AstPort final : public AstNode { - // A port (in/out/inout) on a module -private: - int m_pinNum; // Pin number - string m_name; // Name of pin -public: - AstPort(FileLine* fl, int pinnum, const string& name) - : ASTGEN_SUPER_Port(fl) - , m_pinNum{pinnum} - , m_name{name} {} - ASTNODE_NODE_FUNCS(Port) - virtual string name() const override { return m_name; } // * = Port name - int pinNum() const { return m_pinNum; } // * = Pin number, for order based instantiation - AstNode* exprp() const { return op1p(); } // op1 = Expression connected to port -}; - -//###################################################################### - -class AstParseRef final : public AstNode { - // A reference to a variable, function or task - // We don't know which at parse time due to bison constraints - // The link stages will replace this with AstVarRef, or AstTaskRef, etc. - // Parents: math|stmt - // Children: TEXT|DOT|SEL*|TASK|FUNC (or expression under sel) -private: - VParseRefExp m_expect; // Type we think it should resolve to - string m_name; - -public: - AstParseRef(FileLine* fl, VParseRefExp expect, const string& name, AstNode* lhsp = nullptr, - AstNodeFTaskRef* ftaskrefp = nullptr) - : ASTGEN_SUPER_ParseRef(fl) - , m_expect{expect} - , m_name{name} { - setNOp1p(lhsp); - setNOp2p(ftaskrefp); - } - ASTNODE_NODE_FUNCS(ParseRef) - virtual void dump(std::ostream& str) const override; - virtual string name() const override { return m_name; } // * = Var name - virtual bool same(const AstNode* samep) const override { - const AstParseRef* const asamep = static_cast(samep); - return (expect() == asamep->expect() && m_name == asamep->m_name); - } - virtual void name(const string& name) override { m_name = name; } - VParseRefExp expect() const { return m_expect; } - void expect(VParseRefExp exp) { m_expect = exp; } - // op1 = Components - AstNode* lhsp() const { return op1p(); } // op1 = List of statements - AstNode* ftaskrefp() const { return op2p(); } // op2 = Function/task reference - void ftaskrefp(AstNodeFTaskRef* nodep) { setNOp2p(nodep); } // op2 = Function/task reference -}; - -class AstClassOrPackageRef final : public AstNode { -private: - string m_name; - // Node not NodeModule to appease some early parser usage - AstNode* m_classOrPackageNodep; // Package hierarchy -public: - AstClassOrPackageRef(FileLine* fl, const string& name, AstNode* classOrPackageNodep, - AstNode* paramsp) - : ASTGEN_SUPER_ClassOrPackageRef(fl) - , m_name{name} - , m_classOrPackageNodep{classOrPackageNodep} { - addNOp4p(paramsp); - } - ASTNODE_NODE_FUNCS(ClassOrPackageRef) - // METHODS - virtual const char* broken() const override { - BROKEN_RTN(m_classOrPackageNodep && !m_classOrPackageNodep->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { - if (m_classOrPackageNodep && m_classOrPackageNodep->clonep()) { - m_classOrPackageNodep = m_classOrPackageNodep->clonep(); - } - } - virtual bool same(const AstNode* samep) const override { - return (m_classOrPackageNodep - == static_cast(samep)->m_classOrPackageNodep); - } - virtual void dump(std::ostream& str = std::cout) const override; - virtual string name() const override { return m_name; } // * = Var name - AstNode* classOrPackageNodep() const { return m_classOrPackageNodep; } - void classOrPackageNodep(AstNode* nodep) { m_classOrPackageNodep = nodep; } - AstNodeModule* classOrPackagep() const { - AstNode* foundp = m_classOrPackageNodep; - while (auto* const anodep = VN_CAST(foundp, Typedef)) foundp = anodep->subDTypep(); - if (auto* const anodep = VN_CAST(foundp, ClassRefDType)) foundp = anodep->classp(); - return VN_CAST(foundp, NodeModule); - } - AstPackage* packagep() const { return VN_CAST(classOrPackageNodep(), Package); } - void classOrPackagep(AstNodeModule* nodep) { m_classOrPackageNodep = nodep; } - AstPin* paramsp() const { return VN_AS(op4p(), Pin); } -}; - -class AstDot final : public AstNode { - // A dot separating paths in an AstVarXRef, AstFuncRef or AstTaskRef - // These are eliminated in the link stage - const bool m_colon; // Is a "::" instead of a "." (lhs must be package/class) -public: - AstDot(FileLine* fl, bool colon, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Dot(fl) - , m_colon{colon} { - setOp1p(lhsp); - setOp2p(rhsp); - } - ASTNODE_NODE_FUNCS(Dot) - // For parser, make only if non-null package - static AstNode* newIfPkg(FileLine* fl, AstNode* packageOrClassp, AstNode* rhsp) { - if (!packageOrClassp) return rhsp; - return new AstDot(fl, true, packageOrClassp, rhsp); - } - virtual void dump(std::ostream& str) const override; - AstNode* lhsp() const { return op1p(); } - void rhsp(AstNode* nodep) { setOp2p(nodep); } - AstNode* rhsp() const { return op2p(); } - bool colon() const { return m_colon; } -}; - -class AstUnbounded final : public AstNodeMath { - // A $ in the parser, used for unbounded and queues - // Due to where is used, treated as Signed32 -public: - explicit AstUnbounded(FileLine* fl) - : ASTGEN_SUPER_Unbounded(fl) { - dtypeSetSigned32(); - } - ASTNODE_NODE_FUNCS(Unbounded) - virtual string emitVerilog() override { return "$"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } -}; - -//###################################################################### - -class AstTask final : public AstNodeFTask { - // A task inside a module -public: - AstTask(FileLine* fl, const string& name, AstNode* stmtp) - : ASTGEN_SUPER_Task(fl, name, stmtp) {} - ASTNODE_NODE_FUNCS(Task) -}; - -class AstFunc final : public AstNodeFTask { - // A function inside a module -public: - AstFunc(FileLine* fl, const string& name, AstNode* stmtp, AstNode* fvarsp) - : ASTGEN_SUPER_Func(fl, name, stmtp) { - addNOp1p(fvarsp); - } - ASTNODE_NODE_FUNCS(Func) - virtual bool hasDType() const override { return true; } -}; - -class AstTaskRef final : public AstNodeFTaskRef { - // A reference to a task -public: - AstTaskRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp) - : ASTGEN_SUPER_TaskRef(fl, true, namep, pinsp) { - statement(true); - } - AstTaskRef(FileLine* fl, const string& name, AstNode* pinsp) - : ASTGEN_SUPER_TaskRef(fl, true, name, pinsp) {} - ASTNODE_NODE_FUNCS(TaskRef) -}; - -class AstFuncRef final : public AstNodeFTaskRef { - // A reference to a function -public: - AstFuncRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp) - : ASTGEN_SUPER_FuncRef(fl, false, namep, pinsp) {} - AstFuncRef(FileLine* fl, const string& name, AstNode* pinsp) - : ASTGEN_SUPER_FuncRef(fl, false, name, pinsp) {} - ASTNODE_NODE_FUNCS(FuncRef) - virtual bool hasDType() const override { return true; } -}; - -class AstDpiExport final : public AstNode { - // We could put an AstNodeFTaskRef instead of the verilog function name, - // however we're not *calling* it, so that seems somehow wrong. - // (Probably AstNodeFTaskRef should be renamed AstNodeFTaskCall and have-a AstNodeFTaskRef) -private: - string m_name; // Name of function - string m_cname; // Name of function on c side -public: - AstDpiExport(FileLine* fl, const string& vname, const string& cname) - : ASTGEN_SUPER_DpiExport(fl) - , m_name{vname} - , m_cname{cname} {} - ASTNODE_NODE_FUNCS(DpiExport) - virtual string name() const override { return m_name; } - virtual void name(const string& name) override { m_name = name; } - string cname() const { return m_cname; } - void cname(const string& cname) { m_cname = cname; } -}; - -class AstWithParse final : public AstNodeStmt { - // In early parse, FUNC(index) WITH equation-using-index - // Replaced with AstWith - // Parents: math|stmt - // Children: funcref, math -public: - AstWithParse(FileLine* fl, bool stmt, AstNode* funcrefp, AstNode* exprp) - : ASTGEN_SUPER_WithParse(fl) { - statement(stmt); - setOp1p(funcrefp); - addNOp2p(exprp); - } - ASTNODE_NODE_FUNCS(WithParse) - virtual bool same(const AstNode* /*samep*/) const override { return true; } - // - AstNode* funcrefp() const { return op1p(); } - AstNode* exprp() const { return op2p(); } -}; - -class AstLambdaArgRef final : public AstNodeMath { - // Lambda argument usage - // These are not AstVarRefs because we need to be able to delete/clone lambdas during - // optimizations and AstVar's are painful to remove. -private: - string m_name; // Name of variable - bool m_index; // Index, not value - -public: - AstLambdaArgRef(FileLine* fl, const string& name, bool index) - : ASTGEN_SUPER_LambdaArgRef(fl) - , m_name{name} - , m_index(index) {} - ASTNODE_NODE_FUNCS(LambdaArgRef) - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual string emitVerilog() override { return name(); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual bool hasDType() const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } - virtual string name() const override { return m_name; } // * = Var name - virtual void name(const string& name) override { m_name = name; } - bool index() const { return m_index; } -}; - -class AstWith final : public AstNodeStmt { - // Used as argument to method, then to AstCMethodHard - // dtypep() contains the with lambda's return dtype - // Parents: funcref (similar to AstArg) - // Children: LambdaArgRef that declares the item variable - // Children: LambdaArgRef that declares the item.index variable - // Children: math (equation establishing the with) -public: - AstWith(FileLine* fl, AstLambdaArgRef* indexArgRefp, AstLambdaArgRef* valueArgRefp, - AstNode* exprp) - : ASTGEN_SUPER_With(fl) { - addOp1p(indexArgRefp); - addOp2p(valueArgRefp); - addNOp3p(exprp); - } - ASTNODE_NODE_FUNCS(With) - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual bool hasDType() const override { return true; } - virtual const char* broken() const override { - BROKEN_RTN(!indexArgRefp()); // varp needed to know lambda's arg dtype - BROKEN_RTN(!valueArgRefp()); // varp needed to know lambda's arg dtype - return nullptr; - } - // - AstLambdaArgRef* indexArgRefp() const { return VN_AS(op1p(), LambdaArgRef); } - AstLambdaArgRef* valueArgRefp() const { return VN_AS(op2p(), LambdaArgRef); } - AstNode* exprp() const { return op3p(); } -}; - -//###################################################################### - -class AstSenItem final : public AstNode { - // Parents: SENTREE - // Children: (optional) VARREF -private: - VEdgeType m_edgeType; // Edge type -public: - class Combo {}; // for creator type-overload selection - class Illegal {}; // for creator type-overload selection - class Initial {}; // for creator type-overload selection - class Settle {}; // for creator type-overload selection - class Never {}; // for creator type-overload selection - AstSenItem(FileLine* fl, VEdgeType edgeType, AstNode* varrefp) - : ASTGEN_SUPER_SenItem(fl) - , m_edgeType{edgeType} { - setOp1p(varrefp); - } - AstSenItem(FileLine* fl, Combo) - : ASTGEN_SUPER_SenItem(fl) - , m_edgeType{VEdgeType::ET_COMBO} {} - AstSenItem(FileLine* fl, Illegal) - : ASTGEN_SUPER_SenItem(fl) - , m_edgeType{VEdgeType::ET_ILLEGAL} {} - AstSenItem(FileLine* fl, Initial) - : ASTGEN_SUPER_SenItem(fl) - , m_edgeType{VEdgeType::ET_INITIAL} {} - AstSenItem(FileLine* fl, Settle) - : ASTGEN_SUPER_SenItem(fl) - , m_edgeType{VEdgeType::ET_SETTLE} {} - AstSenItem(FileLine* fl, Never) - : ASTGEN_SUPER_SenItem(fl) - , m_edgeType{VEdgeType::ET_NEVER} {} - ASTNODE_NODE_FUNCS(SenItem) - virtual void dump(std::ostream& str) const override; - virtual bool same(const AstNode* samep) const override { - return edgeType() == static_cast(samep)->edgeType(); - } - VEdgeType edgeType() const { return m_edgeType; } // * = Posedge/negedge - void edgeType(VEdgeType type) { - m_edgeType = type; - editCountInc(); - } // * = Posedge/negedge - AstNode* sensp() const { return op1p(); } // op1 = Signal sensitized - AstNodeVarRef* varrefp() const { - return VN_CAST(op1p(), NodeVarRef); - } // op1 = Signal sensitized - // - bool isClocked() const { return edgeType().clockedStmt(); } - bool isCombo() const { return edgeType() == VEdgeType::ET_COMBO; } - bool isInitial() const { return edgeType() == VEdgeType::ET_INITIAL; } - bool isIllegal() const { return edgeType() == VEdgeType::ET_ILLEGAL; } - bool isSettle() const { return edgeType() == VEdgeType::ET_SETTLE; } - bool isNever() const { return edgeType() == VEdgeType::ET_NEVER; } - bool hasVar() const { return !(isCombo() || isInitial() || isSettle() || isNever()); } -}; - -class AstSenTree final : public AstNode { - // A list of senitems - // Parents: MODULE | SBLOCK - // Children: SENITEM list -private: - bool m_multi = false; // Created from combo logic by ORing multiple clock domains -public: - AstSenTree(FileLine* fl, AstSenItem* sensesp) - : ASTGEN_SUPER_SenTree(fl) { - addNOp1p(sensesp); - } - ASTNODE_NODE_FUNCS(SenTree) - virtual void dump(std::ostream& str) const override; - virtual bool maybePointedTo() const override { return true; } - bool isMulti() const { return m_multi; } - // op1 = Sensitivity list - AstSenItem* sensesp() const { return VN_AS(op1p(), SenItem); } - void addSensesp(AstSenItem* nodep) { addOp1p(nodep); } - void multi(bool flag) { m_multi = true; } - // METHODS - bool hasClocked() const; // Includes a clocked statement - bool hasSettle() const; // Includes a SETTLE SenItem - bool hasInitial() const; // Includes a INITIAL SenItem - bool hasCombo() const; // Includes a COMBO SenItem -}; - -class AstFinal final : public AstNodeProcedure { -public: - AstFinal(FileLine* fl, AstNode* bodysp) - : ASTGEN_SUPER_Final(fl, bodysp) {} - ASTNODE_NODE_FUNCS(Final) -}; - -class AstInitial final : public AstNodeProcedure { -public: - AstInitial(FileLine* fl, AstNode* bodysp) - : ASTGEN_SUPER_Initial(fl, bodysp) {} - ASTNODE_NODE_FUNCS(Initial) -}; - -class AstInitialAutomatic final : public AstNodeProcedure { - // Automatic variable initialization - // That is, it runs every function start, or class construction -public: - AstInitialAutomatic(FileLine* fl, AstNode* bodysp) - : ASTGEN_SUPER_InitialAutomatic(fl, bodysp) {} - ASTNODE_NODE_FUNCS(InitialAutomatic) -}; - -class AstInitialStatic final : public AstNodeProcedure { - // Static variable initialization - // That is, it runs at the beginning of simulation, before 'initial' blocks -public: - AstInitialStatic(FileLine* fl, AstNode* bodysp) - : ASTGEN_SUPER_InitialStatic(fl, bodysp) {} - ASTNODE_NODE_FUNCS(InitialStatic) -}; - -class AstAlways final : public AstNodeProcedure { - const VAlwaysKwd m_keyword; - -public: - AstAlways(FileLine* fl, VAlwaysKwd keyword, AstSenTree* sensesp, AstNode* bodysp) - : ASTGEN_SUPER_Always(fl, bodysp) - , m_keyword{keyword} { - addNOp1p(sensesp); - } - ASTNODE_NODE_FUNCS(Always) - // - virtual void dump(std::ostream& str) const override; - AstSenTree* sensesp() const { return VN_AS(op1p(), SenTree); } // op1 = Sensitivity list - void sensesp(AstSenTree* nodep) { setOp1p(nodep); } - VAlwaysKwd keyword() const { return m_keyword; } -}; - -class AstAlwaysPostponed final : public AstNodeProcedure { - // Like always but postponement scheduling region - -public: - AstAlwaysPostponed(FileLine* fl, AstNode* bodysp) - : ASTGEN_SUPER_AlwaysPostponed(fl, bodysp) {} - ASTNODE_NODE_FUNCS(AlwaysPostponed) -}; - -class AstAlwaysPost final : public AstNodeProcedure { - // Like always but post assignments for memory assignment IFs -public: - AstAlwaysPost(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp) - : ASTGEN_SUPER_AlwaysPost(fl, bodysp) { - addNOp1p(sensesp); - } - ASTNODE_NODE_FUNCS(AlwaysPost) -}; - -class AstAlwaysPublic final : public AstNodeStmt { - // "Fake" sensitivity created by /*verilator public_flat_rw @(edgelist)*/ - // Body statements are just AstVarRefs to the public signals -public: - AstAlwaysPublic(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp) - : ASTGEN_SUPER_AlwaysPublic(fl) { - addNOp1p(sensesp); - addNOp2p(bodysp); - } - ASTNODE_NODE_FUNCS(AlwaysPublic) - virtual bool same(const AstNode* /*samep*/) const override { return true; } - // - AstSenTree* sensesp() const { return VN_AS(op1p(), SenTree); } // op1 = Sensitivity list - AstNode* bodysp() const { return op2p(); } // op2 = Statements to evaluate - void addStmtp(AstNode* nodep) { addOp2p(nodep); } - // Special accessors - bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); } - bool isFirstInMyListOfStatements(AstNode* n) const override { return n == bodysp(); } -}; - -class AstAssign final : public AstNodeAssign { -public: - AstAssign(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* timingControlp = nullptr) - : ASTGEN_SUPER_Assign(fl, lhsp, rhsp, timingControlp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(Assign) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAssign(this->fileline(), lhsp, rhsp); - } - virtual bool brokeLhsMustBeLvalue() const override { return true; } -}; - -class AstAssignAlias final : public AstNodeAssign { - // Like AstAssignW, but a true bidirect interconnection alias - // If both sides are wires, there's no LHS vs RHS, -public: - AstAssignAlias(FileLine* fl, AstVarRef* lhsp, AstVarRef* rhsp) - : ASTGEN_SUPER_AssignAlias(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(AssignAlias) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - V3ERROR_NA_RETURN(nullptr); - } - virtual bool brokeLhsMustBeLvalue() const override { return false; } -}; - -class AstAssignDly final : public AstNodeAssign { -public: - AstAssignDly(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* timingControlp = nullptr) - : ASTGEN_SUPER_AssignDly(fl, lhsp, rhsp, timingControlp) {} - ASTNODE_NODE_FUNCS(AssignDly) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAssignDly(this->fileline(), lhsp, rhsp); - } - virtual bool isGateOptimizable() const override { return false; } - virtual string verilogKwd() const override { return "<="; } - virtual bool brokeLhsMustBeLvalue() const override { return true; } -}; - -class AstAssignW final : public AstNodeAssign { - // Like assign, but wire/assign's in verilog, the only setting of the specified variable -public: - AstAssignW(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_AssignW(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(AssignW) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAssignW(this->fileline(), lhsp, rhsp); - } - virtual bool brokeLhsMustBeLvalue() const override { return true; } - AstAlways* convertToAlways() { - AstNode* const lhs1p = lhsp()->unlinkFrBack(); - AstNode* const rhs1p = rhsp()->unlinkFrBack(); - AstAlways* const newp = new AstAlways(fileline(), VAlwaysKwd::ALWAYS, nullptr, - new AstAssign(fileline(), lhs1p, rhs1p)); - replaceWith(newp); // User expected to then deleteTree(); - return newp; - } -}; - -class AstAssignVarScope final : public AstNodeAssign { - // Assign two VarScopes to each other -public: - AstAssignVarScope(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_AssignVarScope(fl, lhsp, rhsp) { - dtypeFrom(rhsp); - } - ASTNODE_NODE_FUNCS(AssignVarScope) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAssignVarScope(this->fileline(), lhsp, rhsp); - } - virtual bool brokeLhsMustBeLvalue() const override { return false; } -}; - -class AstPull final : public AstNode { -private: - bool m_direction; - -public: - AstPull(FileLine* fl, AstNode* lhsp, bool direction) - : ASTGEN_SUPER_Pull(fl) { - setOp1p(lhsp); - m_direction = direction; - } - ASTNODE_NODE_FUNCS(Pull) - virtual bool same(const AstNode* samep) const override { - return direction() == static_cast(samep)->direction(); - } - void lhsp(AstNode* np) { setOp1p(np); } - AstNode* lhsp() const { return op1p(); } // op1 = Assign to - uint32_t direction() const { return (uint32_t)m_direction; } -}; - -class AstAssignForce final : public AstNodeAssign { - // Procedural 'force' statement -public: - AstAssignForce(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_AssignForce(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(AssignForce) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAssignForce{this->fileline(), lhsp, rhsp}; - } - virtual bool brokeLhsMustBeLvalue() const override { return true; } -}; - -class AstRelease final : public AstNodeStmt { - // Procedural 'release' statement -public: - AstRelease(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_Release(fl) { - setOp1p(lhsp); - } - ASTNODE_NODE_FUNCS(Release); - AstNode* lhsp() const { return op1p(); } -}; - -class AstAssignPre final : public AstNodeAssign { - // Like Assign, but predelayed assignment requiring special order handling -public: - AstAssignPre(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_AssignPre(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(AssignPre) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAssignPre(this->fileline(), lhsp, rhsp); - } - virtual bool brokeLhsMustBeLvalue() const override { return true; } -}; - -class AstAssignPost final : public AstNodeAssign { - // Like Assign, but predelayed assignment requiring special order handling -public: - AstAssignPost(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_AssignPost(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(AssignPost) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAssignPost(this->fileline(), lhsp, rhsp); - } - virtual bool brokeLhsMustBeLvalue() const override { return true; } -}; - -class AstDpiExportUpdated final : public AstNodeStmt { - // Denotes that the referenced variable may have been updated via a DPI Export -public: - AstDpiExportUpdated(FileLine* fl, AstVarScope* varScopep) - : ASTGEN_SUPER_DpiExportUpdated(fl) { - addOp1p(new AstVarRef{fl, varScopep, VAccess::WRITE}); - } - ASTNODE_NODE_FUNCS(DpiExportUpdated) - AstVarScope* varScopep() const { return VN_AS(op1p(), VarRef)->varScopep(); } -}; - -class AstExprStmt final : public AstNodeMath { - // Perform a statement, often assignment inside an expression/math node, - // the parent gets passed the 'resultp()'. - // resultp is evaluated AFTER the statement(s). -public: - AstExprStmt(FileLine* fl, AstNode* stmtsp, AstNode* resultp) - : ASTGEN_SUPER_ExprStmt(fl) { - addOp1p(stmtsp); - setOp2p(resultp); // Possibly in future nullptr could mean return rhsp() - dtypeFrom(resultp); - } - ASTNODE_NODE_FUNCS(ExprStmt) - // ACCESSORS - AstNode* stmtsp() const { return op1p(); } - void addStmtsp(AstNode* nodep) { addOp1p(nodep); } - AstNode* resultp() const { return op2p(); } - // METHODS - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } - virtual bool same(const AstNode*) const override { return true; } -}; - -class AstComment final : public AstNodeStmt { - // Some comment to put into the output stream - // Parents: {statement list} - // Children: none -private: - const bool m_showAt; // Show "at " - const string m_name; // Text of comment -public: - AstComment(FileLine* fl, const string& name, bool showAt = false) - : ASTGEN_SUPER_Comment(fl) - , m_showAt{showAt} - , m_name{name} {} - ASTNODE_NODE_FUNCS(Comment) - virtual string name() const override { return m_name; } // * = Text - virtual bool same(const AstNode* samep) const override { - return true; - } // Ignore name in comments - virtual bool showAt() const { return m_showAt; } -}; - -class AstCond final : public AstNodeCond { - // Conditional ?: statement - // Parents: MATH - // Children: MATH -public: - AstCond(FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p) - : ASTGEN_SUPER_Cond(fl, condp, expr1p, expr2p) {} - ASTNODE_NODE_FUNCS(Cond) - virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) override { - return new AstCond(this->fileline(), condp, expr1p, expr2p); - } -}; - -class AstCondBound final : public AstNodeCond { - // Conditional ?: statement, specially made for safety checking of array bounds - // Parents: MATH - // Children: MATH -public: - AstCondBound(FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p) - : ASTGEN_SUPER_CondBound(fl, condp, expr1p, expr2p) {} - ASTNODE_NODE_FUNCS(CondBound) - virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) override { - return new AstCondBound(this->fileline(), condp, expr1p, expr2p); - } -}; - -class AstCoverDecl final : public AstNodeStmt { - // Coverage analysis point declaration - // Parents: {statement list} - // Children: none -private: - AstCoverDecl* m_dataDeclp; // [After V3CoverageJoin] Pointer to duplicate declaration to get - // data from instead - string m_page; - string m_text; - string m_hier; - string m_linescov; - int m_offset; // Offset column numbers to uniq-ify IFs - int m_binNum; // Set by V3EmitCSyms to tell final V3Emit what to increment -public: - AstCoverDecl(FileLine* fl, const string& page, const string& comment, const string& linescov, - int offset) - : ASTGEN_SUPER_CoverDecl(fl) { - m_page = page; - m_text = comment; - m_linescov = linescov; - m_offset = offset; - m_binNum = 0; - m_dataDeclp = nullptr; - } - ASTNODE_NODE_FUNCS(CoverDecl) - virtual const char* broken() const override { - BROKEN_RTN(m_dataDeclp && !m_dataDeclp->brokeExists()); - if (m_dataDeclp && m_dataDeclp->m_dataDeclp) { // Avoid O(n^2) accessing - v3fatalSrc("dataDeclp should point to real data, not be a list"); - } - return nullptr; - } - virtual void cloneRelink() override { - if (m_dataDeclp && m_dataDeclp->clonep()) m_dataDeclp = m_dataDeclp->clonep(); - } - virtual void dump(std::ostream& str) const override; - virtual int instrCount() const override { return 1 + 2 * INSTR_COUNT_LD; } - virtual bool maybePointedTo() const override { return true; } - void binNum(int flag) { m_binNum = flag; } - int binNum() const { return m_binNum; } - int offset() const { return m_offset; } - const string& comment() const { return m_text; } // text to insert in code - const string& linescov() const { return m_linescov; } - const string& page() const { return m_page; } - const string& hier() const { return m_hier; } - void hier(const string& flag) { m_hier = flag; } - void comment(const string& flag) { m_text = flag; } - virtual bool same(const AstNode* samep) const override { - const AstCoverDecl* const asamep = static_cast(samep); - return (fileline() == asamep->fileline() && linescov() == asamep->linescov() - && hier() == asamep->hier() && comment() == asamep->comment()); - } - virtual bool isPredictOptimizable() const override { return false; } - void dataDeclp(AstCoverDecl* nodep) { m_dataDeclp = nodep; } - // dataDecl nullptr means "use this one", but often you want "this" to - // indicate to get data from here - AstCoverDecl* dataDeclNullp() const { return m_dataDeclp; } - AstCoverDecl* dataDeclThisp() { return dataDeclNullp() ? dataDeclNullp() : this; } -}; - -class AstCoverInc final : public AstNodeStmt { - // Coverage analysis point; increment coverage count - // Parents: {statement list} - // Children: none -private: - AstCoverDecl* m_declp; // [After V3Coverage] Pointer to declaration -public: - AstCoverInc(FileLine* fl, AstCoverDecl* declp) - : ASTGEN_SUPER_CoverInc(fl) - , m_declp{declp} {} - ASTNODE_NODE_FUNCS(CoverInc) - virtual const char* broken() const override { - BROKEN_RTN(!declp()->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { - if (m_declp->clonep()) m_declp = m_declp->clonep(); - } - virtual void dump(std::ostream& str) const override; - virtual int instrCount() const override { return 1 + 2 * INSTR_COUNT_LD; } - virtual bool same(const AstNode* samep) const override { - return declp() == static_cast(samep)->declp(); - } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isOutputter() const override { return true; } - // but isPure() true - AstCoverDecl* declp() const { return m_declp; } // Where defined -}; - -class AstCoverToggle final : public AstNodeStmt { - // Toggle analysis of given signal - // Parents: MODULE - // Children: AstCoverInc, orig var, change det var -public: - AstCoverToggle(FileLine* fl, AstCoverInc* incp, AstNode* origp, AstNode* changep) - : ASTGEN_SUPER_CoverToggle(fl) { - setOp1p(incp); - setOp2p(origp); - setOp3p(changep); - } - ASTNODE_NODE_FUNCS(CoverToggle) - virtual int instrCount() const override { return 3 + INSTR_COUNT_BRANCH + INSTR_COUNT_LD; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return true; } - virtual bool isOutputter() const override { - return false; // Though the AstCoverInc under this is an outputter - } - // but isPure() true - AstCoverInc* incp() const { return VN_AS(op1p(), CoverInc); } - void incp(AstCoverInc* nodep) { setOp1p(nodep); } - AstNode* origp() const { return op2p(); } - AstNode* changep() const { return op3p(); } -}; - -class AstDelay final : public AstNodeStmt { - // Delay statement -public: - AstDelay(FileLine* fl, AstNode* lhsp, AstNode* stmtsp) - : ASTGEN_SUPER_Delay(fl) { - setOp1p(lhsp); - setNOp2p(stmtsp); - } - ASTNODE_NODE_FUNCS(Delay) - virtual bool same(const AstNode* /*samep*/) const override { return true; } - // - AstNode* lhsp() const { return op1p(); } // op1 = delay value - void lhsp(AstNode* nodep) { setOp1p(nodep); } - void stmtsp(AstNode* nodep) { setOp2p(nodep); } // op2 = statements under delay - AstNode* stmtsp() const { return op2p(); } -}; - -class AstGenCase final : public AstNodeCase { - // Generate Case statement - // Parents: {statement list} - // exprp Children: MATHs - // casesp Children: CASEITEMs -public: - AstGenCase(FileLine* fl, AstNode* exprp, AstNode* casesp) - : ASTGEN_SUPER_GenCase(fl, exprp, casesp) {} - ASTNODE_NODE_FUNCS(GenCase) -}; - -class AstCase final : public AstNodeCase { - // Case statement - // Parents: {statement list} - // exprp Children: MATHs - // casesp Children: CASEITEMs -private: - VCaseType m_casex; // 0=case, 1=casex, 2=casez - bool m_fullPragma = false; // Synthesis full_case - bool m_parallelPragma = false; // Synthesis parallel_case - bool m_uniquePragma = false; // unique case - bool m_unique0Pragma = false; // unique0 case - bool m_priorityPragma = false; // priority case -public: - AstCase(FileLine* fl, VCaseType casex, AstNode* exprp, AstNode* casesp) - : ASTGEN_SUPER_Case(fl, exprp, casesp) - , m_casex{casex} {} - ASTNODE_NODE_FUNCS(Case) - virtual string verilogKwd() const override { - return casez() ? "casez" : casex() ? "casex" : "case"; - } - virtual bool same(const AstNode* samep) const override { - return m_casex == static_cast(samep)->m_casex; - } - bool casex() const { return m_casex == VCaseType::CT_CASEX; } - bool casez() const { return m_casex == VCaseType::CT_CASEZ; } - bool caseInside() const { return m_casex == VCaseType::CT_CASEINSIDE; } - bool caseSimple() const { return m_casex == VCaseType::CT_CASE; } - void caseInsideSet() { m_casex = VCaseType::CT_CASEINSIDE; } - bool fullPragma() const { return m_fullPragma; } - void fullPragma(bool flag) { m_fullPragma = flag; } - bool parallelPragma() const { return m_parallelPragma; } - void parallelPragma(bool flag) { m_parallelPragma = flag; } - bool uniquePragma() const { return m_uniquePragma; } - void uniquePragma(bool flag) { m_uniquePragma = flag; } - bool unique0Pragma() const { return m_unique0Pragma; } - void unique0Pragma(bool flag) { m_unique0Pragma = flag; } - bool priorityPragma() const { return m_priorityPragma; } - void priorityPragma(bool flag) { m_priorityPragma = flag; } -}; - -class AstCaseItem final : public AstNode { - // Single item of a case statement - // Parents: CASE - // condsp Children: MATH (Null condition used for default block) - // bodysp Children: Statements -public: - AstCaseItem(FileLine* fl, AstNode* condsp, AstNode* bodysp) - : ASTGEN_SUPER_CaseItem(fl) { - addNOp1p(condsp); - addNOp2p(bodysp); - } - ASTNODE_NODE_FUNCS(CaseItem) - virtual int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } - AstNode* condsp() const { return op1p(); } // op1 = list of possible matching expressions - AstNode* bodysp() const { return op2p(); } // op2 = what to do - void condsp(AstNode* nodep) { setOp1p(nodep); } - void addBodysp(AstNode* newp) { addOp2p(newp); } - bool isDefault() const { return condsp() == nullptr; } - bool isFirstInMyListOfStatements(AstNode* n) const override { return n == bodysp(); } -}; - -class AstSFormatF final : public AstNode { - // Convert format to string, generally under an AstDisplay or AstSFormat - // Also used as "real" function for /*verilator sformat*/ functions - string m_text; - const bool m_hidden; // Under display, etc - bool m_hasFormat; // Has format code - const char m_missingArgChar; // Format code when argument without format, 'h'/'o'/'b' - VTimescale m_timeunit; // Parent module time unit -public: - class NoFormat {}; - AstSFormatF(FileLine* fl, const string& text, bool hidden, AstNode* exprsp, - char missingArgChar = 'd') - : ASTGEN_SUPER_SFormatF(fl) - , m_text{text} - , m_hidden{hidden} - , m_hasFormat{true} - , m_missingArgChar{missingArgChar} { - dtypeSetString(); - addNOp1p(exprsp); - addNOp2p(nullptr); - } - AstSFormatF(FileLine* fl, NoFormat, AstNode* exprsp, char missingArgChar = 'd', - bool hidden = true) - : ASTGEN_SUPER_SFormatF(fl) - , m_text{""} - , m_hidden{hidden} - , m_hasFormat{false} - , m_missingArgChar{missingArgChar} { - dtypeSetString(); - addNOp1p(exprsp); - addNOp2p(nullptr); - } - ASTNODE_NODE_FUNCS(SFormatF) - virtual string name() const override { return m_text; } - virtual int instrCount() const override { return INSTR_COUNT_PLI; } - virtual bool hasDType() const override { return true; } - virtual bool same(const AstNode* samep) const override { - return text() == static_cast(samep)->text(); - } - virtual string verilogKwd() const override { return "$sformatf"; } - void addExprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output - AstNode* exprsp() const { return op1p(); } // op1 = Expressions to output - string text() const { return m_text; } // * = Text to display - void text(const string& text) { m_text = text; } - AstScopeName* scopeNamep() const { return VN_AS(op2p(), ScopeName); } - void scopeNamep(AstNode* nodep) { setNOp2p(nodep); } - bool formatScopeTracking() const { // Track scopeNamep(); Ok if false positive - return (name().find("%m") != string::npos || name().find("%M") != string::npos); - } - bool hidden() const { return m_hidden; } - void hasFormat(bool flag) { m_hasFormat = flag; } - bool hasFormat() const { return m_hasFormat; } - char missingArgChar() const { return m_missingArgChar; } - void timeunit(const VTimescale& flag) { m_timeunit = flag; } - VTimescale timeunit() const { return m_timeunit; } -}; - -class AstDisplay final : public AstNodeStmt { - // Parents: stmtlist - // Children: file which must be a varref - // Children: SFORMATF to generate print string -private: - VDisplayType m_displayType; - -public: - AstDisplay(FileLine* fl, VDisplayType dispType, const string& text, AstNode* filep, - AstNode* exprsp, char missingArgChar = 'd') - : ASTGEN_SUPER_Display(fl) { - setOp1p(new AstSFormatF(fl, text, true, exprsp, missingArgChar)); - setNOp3p(filep); - m_displayType = dispType; - } - AstDisplay(FileLine* fl, VDisplayType dispType, AstNode* filep, AstNode* exprsp, - char missingArgChar = 'd') - : ASTGEN_SUPER_Display(fl) { - setOp1p(new AstSFormatF(fl, AstSFormatF::NoFormat(), exprsp, missingArgChar)); - setNOp3p(filep); - m_displayType = dispType; - } - ASTNODE_NODE_FUNCS(Display) - virtual void dump(std::ostream& str) const override; - virtual const char* broken() const override { - BROKEN_RTN(!fmtp()); - return nullptr; - } - virtual string verilogKwd() const override { - return (filep() ? string("$f") + string(displayType().ascii()) - : string("$") + string(displayType().ascii())); - } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { - return false; - } // SPECIAL: $display has 'visual' ordering - virtual bool isOutputter() const override { return true; } // SPECIAL: $display makes output - virtual bool isUnlikely() const override { return true; } - virtual bool same(const AstNode* samep) const override { - return displayType() == static_cast(samep)->displayType(); - } - virtual int instrCount() const override { return INSTR_COUNT_PLI; } - VDisplayType displayType() const { return m_displayType; } - void displayType(VDisplayType type) { m_displayType = type; } - // * = Add a newline for $display - bool addNewline() const { return displayType().addNewline(); } - void fmtp(AstSFormatF* nodep) { addOp1p(nodep); } // op1 = To-String formatter - AstSFormatF* fmtp() const { return VN_AS(op1p(), SFormatF); } - AstNode* filep() const { return op3p(); } - void filep(AstNodeVarRef* nodep) { setNOp3p(nodep); } -}; - -class AstDumpCtl final : public AstNodeStmt { - // $dumpon etc - // Parents: expr - // Child: expr based on type of control statement - const VDumpCtlType m_ctlType; // Type of operation -public: - AstDumpCtl(FileLine* fl, VDumpCtlType ctlType, AstNode* exprp = nullptr) - : ASTGEN_SUPER_DumpCtl(fl) - , m_ctlType{ctlType} { - setNOp1p(exprp); - } - ASTNODE_NODE_FUNCS(DumpCtl) - virtual string verilogKwd() const override { return ctlType().ascii(); } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual bool cleanOut() const { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - VDumpCtlType ctlType() const { return m_ctlType; } - AstNode* exprp() const { return op1p(); } // op2 = Expressions to output - void exprp(AstNode* nodep) { setOp1p(nodep); } -}; - -class AstElabDisplay final : public AstNode { - // Parents: stmtlist - // Children: SFORMATF to generate print string -private: - VDisplayType m_displayType; - -public: - AstElabDisplay(FileLine* fl, VDisplayType dispType, AstNode* exprsp) - : ASTGEN_SUPER_ElabDisplay(fl) { - setOp1p(new AstSFormatF(fl, AstSFormatF::NoFormat(), exprsp)); - m_displayType = dispType; - } - ASTNODE_NODE_FUNCS(ElabDisplay) - virtual const char* broken() const override { - BROKEN_RTN(!fmtp()); - return nullptr; - } - virtual string verilogKwd() const override { - return (string("$") + string(displayType().ascii())); - } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { - return false; - } // SPECIAL: $display has 'visual' ordering - virtual bool isOutputter() const override { return true; } // SPECIAL: $display makes output - virtual bool isUnlikely() const override { return true; } - virtual bool same(const AstNode* samep) const override { - return displayType() == static_cast(samep)->displayType(); - } - virtual int instrCount() const override { return INSTR_COUNT_PLI; } - VDisplayType displayType() const { return m_displayType; } - void displayType(VDisplayType type) { m_displayType = type; } - void fmtp(AstSFormatF* nodep) { addOp1p(nodep); } // op1 = To-String formatter - AstSFormatF* fmtp() const { return VN_AS(op1p(), SFormatF); } -}; - -class AstSFormat final : public AstNodeStmt { - // Parents: statement container - // Children: string to load - // Children: SFORMATF to generate print string -public: - AstSFormat(FileLine* fl, AstNode* lhsp, const string& text, AstNode* exprsp, - char missingArgChar = 'd') - : ASTGEN_SUPER_SFormat(fl) { - setOp1p(new AstSFormatF(fl, text, true, exprsp, missingArgChar)); - setOp3p(lhsp); - } - AstSFormat(FileLine* fl, AstNode* lhsp, AstNode* exprsp, char missingArgChar = 'd') - : ASTGEN_SUPER_SFormat(fl) { - setOp1p(new AstSFormatF(fl, AstSFormatF::NoFormat(), exprsp, missingArgChar)); - setOp3p(lhsp); - } - ASTNODE_NODE_FUNCS(SFormat) - virtual const char* broken() const override { - BROKEN_RTN(!fmtp()); - return nullptr; - } - virtual string verilogKwd() const override { return "$sformat"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return true; } - virtual bool isPure() const override { return true; } - virtual bool isOutputter() const override { return false; } - virtual bool cleanOut() const { return false; } - virtual int instrCount() const override { return INSTR_COUNT_PLI; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - void fmtp(AstSFormatF* nodep) { addOp1p(nodep); } // op1 = To-String formatter - AstSFormatF* fmtp() const { return VN_AS(op1p(), SFormatF); } - AstNode* lhsp() const { return op3p(); } - void lhsp(AstNode* nodep) { setOp3p(nodep); } -}; - -class AstSysFuncAsTask final : public AstNodeStmt { - // Call what is normally a system function (with a return) in a non-return context - // Parents: stmtlist - // Children: a system function -public: - AstSysFuncAsTask(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER_SysFuncAsTask(fl) { - addNOp1p(exprsp); - } - ASTNODE_NODE_FUNCS(SysFuncAsTask) - virtual string verilogKwd() const override { return ""; } - virtual bool isGateOptimizable() const override { return true; } - virtual bool isPredictOptimizable() const override { return true; } - virtual bool isPure() const override { return true; } - virtual bool isOutputter() const override { return false; } - virtual int instrCount() const override { return 0; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* lhsp() const { return op1p(); } // op1 = Expressions to eval - void lhsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to eval -}; - -class AstSysIgnore final : public AstNodeStmt { - // Parents: stmtlist - // Children: varrefs or exprs -public: - AstSysIgnore(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER_SysIgnore(fl) { - addNOp1p(exprsp); - } - ASTNODE_NODE_FUNCS(SysIgnore) - virtual string verilogKwd() const override { return "$ignored"; } - virtual bool isGateOptimizable() const override { return false; } // Though deleted before opt - virtual bool isPredictOptimizable() const override { - return false; - } // Though deleted before opt - virtual bool isPure() const override { return false; } // Though deleted before opt - virtual bool isOutputter() const override { return true; } // Though deleted before opt - virtual int instrCount() const override { return INSTR_COUNT_PLI; } - AstNode* exprsp() const { return op1p(); } // op1 = Expressions to output - void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output -}; - -class AstFClose final : public AstNodeStmt { - // Parents: stmtlist - // Children: file which must be a varref -public: - AstFClose(FileLine* fl, AstNode* filep) - : ASTGEN_SUPER_FClose(fl) { - setNOp2p(filep); - } - ASTNODE_NODE_FUNCS(FClose) - virtual string verilogKwd() const override { return "$fclose"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual bool isUnlikely() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* filep() const { return op2p(); } - void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } -}; - -class AstFOpen final : public AstNodeStmt { - // Although a system function in IEEE, here a statement which sets the file pointer (MCD) -public: - AstFOpen(FileLine* fl, AstNode* filep, AstNode* filenamep, AstNode* modep) - : ASTGEN_SUPER_FOpen(fl) { - setOp1p(filep); - setOp2p(filenamep); - setOp3p(modep); - } - ASTNODE_NODE_FUNCS(FOpen) - virtual string verilogKwd() const override { return "$fopen"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual bool isUnlikely() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* filep() const { return op1p(); } - AstNode* filenamep() const { return op2p(); } - AstNode* modep() const { return op3p(); } -}; - -class AstFOpenMcd final : public AstNodeStmt { - // Although a system function in IEEE, here a statement which sets the file pointer (MCD) -public: - AstFOpenMcd(FileLine* fl, AstNode* filep, AstNode* filenamep) - : ASTGEN_SUPER_FOpenMcd(fl) { - setOp1p(filep); - setOp2p(filenamep); - } - ASTNODE_NODE_FUNCS(FOpenMcd) - virtual string verilogKwd() const override { return "$fopen"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual bool isUnlikely() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* filep() const { return op1p(); } - AstNode* filenamep() const { return op2p(); } -}; - -class AstFFlush final : public AstNodeStmt { - // Parents: stmtlist - // Children: file which must be a varref -public: - AstFFlush(FileLine* fl, AstNode* filep) - : ASTGEN_SUPER_FFlush(fl) { - setNOp2p(filep); - } - ASTNODE_NODE_FUNCS(FFlush) - virtual string verilogKwd() const override { return "$fflush"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual bool isUnlikely() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* filep() const { return op2p(); } - void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } -}; - -class AstFRead final : public AstNodeMath { - // Parents: expr - // Children: varrefs to load - // Children: file which must be a varref - // Children: low index - // Children: count -public: - AstFRead(FileLine* fl, AstNode* memp, AstNode* filep, AstNode* startp, AstNode* countp) - : ASTGEN_SUPER_FRead(fl) { - setOp1p(memp); - setOp2p(filep); - setNOp3p(startp); - setNOp4p(countp); - } - ASTNODE_NODE_FUNCS(FRead) - virtual string verilogKwd() const override { return "$fread"; } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering - virtual bool isOutputter() const override { return true; } // SPECIAL: makes output - virtual bool cleanOut() const override { return false; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* memp() const { return op1p(); } - void memp(AstNode* nodep) { setOp1p(nodep); } - AstNode* filep() const { return op2p(); } - void filep(AstNode* nodep) { setOp2p(nodep); } - AstNode* startp() const { return op3p(); } - void startp(AstNode* nodep) { setNOp3p(nodep); } - AstNode* countp() const { return op4p(); } - void countp(AstNode* nodep) { setNOp4p(nodep); } -}; - -class AstFRewind final : public AstNodeMath { - // Parents: stmtlist - // Children: file which must be a varref -public: - AstFRewind(FileLine* fl, AstNode* filep) - : ASTGEN_SUPER_FRewind(fl) { - setNOp2p(filep); - } - ASTNODE_NODE_FUNCS(FRewind) - virtual string verilogKwd() const override { return "$frewind"; } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual bool isUnlikely() const override { return true; } - virtual bool cleanOut() const override { return false; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* filep() const { return op2p(); } - void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } -}; - -class AstFTell final : public AstNodeMath { - // Parents: stmtlist - // Children: file which must be a varref -public: - AstFTell(FileLine* fl, AstNode* filep) - : ASTGEN_SUPER_FTell(fl) { - setNOp2p(filep); - } - ASTNODE_NODE_FUNCS(FTell) - virtual string verilogKwd() const override { return "$ftell"; } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual bool isUnlikely() const override { return true; } - virtual bool cleanOut() const override { return false; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* filep() const { return op2p(); } - void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } -}; - -class AstFSeek final : public AstNodeMath { - // Parents: expr - // Children: file which must be a varref - // Children: offset - // Children: operation -public: - AstFSeek(FileLine* fl, AstNode* filep, AstNode* offset, AstNode* operation) - : ASTGEN_SUPER_FSeek(fl) { - setOp2p(filep); - setNOp3p(offset); - setNOp4p(operation); - } - ASTNODE_NODE_FUNCS(FSeek) - virtual string verilogKwd() const override { return "$fseek"; } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering - virtual bool isOutputter() const override { return true; } // SPECIAL: makes output - virtual bool cleanOut() const override { return false; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* filep() const { return op2p(); } - void filep(AstNode* nodep) { setOp2p(nodep); } - AstNode* offset() const { return op3p(); } - void offset(AstNode* nodep) { setNOp3p(nodep); } - AstNode* operation() const { return op4p(); } - void operation(AstNode* nodep) { setNOp4p(nodep); } -}; - -class AstFScanF final : public AstNodeMath { - // Parents: expr - // Children: file which must be a varref - // Children: varrefs to load -private: - string m_text; - -public: - AstFScanF(FileLine* fl, const string& text, AstNode* filep, AstNode* exprsp) - : ASTGEN_SUPER_FScanF(fl) - , m_text{text} { - addNOp1p(exprsp); - setNOp2p(filep); - } - ASTNODE_NODE_FUNCS(FScanF) - virtual string name() const override { return m_text; } - virtual string verilogKwd() const override { return "$fscanf"; } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering - virtual bool isOutputter() const override { return true; } // SPECIAL: makes output - virtual bool cleanOut() const override { return false; } - virtual bool same(const AstNode* samep) const override { - return text() == static_cast(samep)->text(); - } - AstNode* exprsp() const { return op1p(); } // op1 = Expressions to output - void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output - string text() const { return m_text; } // * = Text to display - void text(const string& text) { m_text = text; } - AstNode* filep() const { return op2p(); } - void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } -}; - -class AstSScanF final : public AstNodeMath { - // Parents: expr - // Children: file which must be a varref - // Children: varrefs to load -private: - string m_text; - -public: - AstSScanF(FileLine* fl, const string& text, AstNode* fromp, AstNode* exprsp) - : ASTGEN_SUPER_SScanF(fl) - , m_text{text} { - addNOp1p(exprsp); - setOp2p(fromp); - } - ASTNODE_NODE_FUNCS(SScanF) - virtual string name() const override { return m_text; } - virtual string verilogKwd() const override { return "$sscanf"; } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering - virtual bool isOutputter() const override { return true; } // SPECIAL: makes output - virtual bool cleanOut() const override { return false; } - virtual bool same(const AstNode* samep) const override { - return text() == static_cast(samep)->text(); - } - AstNode* exprsp() const { return op1p(); } // op1 = Expressions to output - void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output - string text() const { return m_text; } // * = Text to display - void text(const string& text) { m_text = text; } - AstNode* fromp() const { return op2p(); } - void fromp(AstNode* nodep) { setOp2p(nodep); } -}; - -class AstNodeReadWriteMem VL_NOT_FINAL : public AstNodeStmt { -private: - const bool m_isHex; // readmemh, not readmemb -public: - AstNodeReadWriteMem(VNType t, FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, - AstNode* lsbp, AstNode* msbp) - : AstNodeStmt(t, fl) - , m_isHex(hex) { - setOp1p(filenamep); - setOp2p(memp); - setNOp3p(lsbp); - setNOp4p(msbp); - } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual bool isUnlikely() const override { return true; } - virtual bool same(const AstNode* samep) const override { - return isHex() == static_cast(samep)->isHex(); - } - bool isHex() const { return m_isHex; } - AstNode* filenamep() const { return op1p(); } - AstNode* memp() const { return op2p(); } - AstNode* lsbp() const { return op3p(); } - AstNode* msbp() const { return op4p(); } - virtual const char* cFuncPrefixp() const = 0; -}; - -class AstReadMem final : public AstNodeReadWriteMem { -public: - AstReadMem(FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, AstNode* lsbp, - AstNode* msbp) - : ASTGEN_SUPER_ReadMem(fl, hex, filenamep, memp, lsbp, msbp) {} - ASTNODE_NODE_FUNCS(ReadMem); - virtual string verilogKwd() const override { return (isHex() ? "$readmemh" : "$readmemb"); } - virtual const char* cFuncPrefixp() const override { return "VL_READMEM_"; } -}; - -class AstWriteMem final : public AstNodeReadWriteMem { -public: - AstWriteMem(FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, AstNode* lsbp, - AstNode* msbp) - : ASTGEN_SUPER_WriteMem(fl, hex, filenamep, memp, lsbp, msbp) {} - ASTNODE_NODE_FUNCS(WriteMem) - virtual string verilogKwd() const override { return (isHex() ? "$writememh" : "$writememb"); } - virtual const char* cFuncPrefixp() const override { return "VL_WRITEMEM_"; } -}; - -class AstMonitorOff final : public AstNodeStmt { - const bool m_off; // Monitor off. Using 0=on allows faster init and comparison - -public: - AstMonitorOff(FileLine* fl, bool off) - : ASTGEN_SUPER_MonitorOff(fl) - , m_off{off} {} - ASTNODE_NODE_FUNCS(MonitorOff) - virtual string verilogKwd() const override { return m_off ? "$monitoroff" : "$monitoron"; } - virtual bool isGateOptimizable() const override { return false; } // Though deleted before opt - virtual bool isPredictOptimizable() const override { - return false; - } // Though deleted before opt - virtual bool isPure() const override { return false; } // Though deleted before opt - virtual bool isOutputter() const override { return true; } // Though deleted before opt - virtual int instrCount() const override { return INSTR_COUNT_PLI; } - virtual bool same(const AstNode* samep) const override { - return m_off == static_cast(samep)->m_off; - } - bool off() const { return m_off; } -}; - -class AstSystemT final : public AstNodeStmt { - // $system used as task -public: - AstSystemT(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_SystemT(fl) { - setOp1p(lhsp); - } - ASTNODE_NODE_FUNCS(SystemT) - virtual string verilogKwd() const override { return "$system"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual bool isUnlikely() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* lhsp() const { return op1p(); } -}; - -class AstSystemF final : public AstNodeMath { - // $system used as function -public: - AstSystemF(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_SystemF(fl) { - setOp1p(lhsp); - } - ASTNODE_NODE_FUNCS(SystemF) - virtual string verilogKwd() const override { return "$system"; } - virtual string emitVerilog() override { return verilogKwd(); } - virtual string emitC() override { return "VL_SYSTEM_%nq(%lw, %P)"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual bool isUnlikely() const override { return true; } - virtual bool cleanOut() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* lhsp() const { return op1p(); } -}; - -class AstValuePlusArgs final : public AstNodeMath { - // Parents: expr - // Child: variable to set. If nullptr then this is a $test$plusargs instead of $value$plusargs -public: - AstValuePlusArgs(FileLine* fl, AstNode* searchp, AstNode* outp) - : ASTGEN_SUPER_ValuePlusArgs(fl) { - setOp1p(searchp); - setOp2p(outp); - } - ASTNODE_NODE_FUNCS(ValuePlusArgs) - virtual string verilogKwd() const override { return "$value$plusargs"; } - virtual string emitVerilog() override { return "%f$value$plusargs(%l, %k%r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return !outp(); } - virtual bool cleanOut() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* searchp() const { return op1p(); } // op1 = Search expression - void searchp(AstNode* nodep) { setOp1p(nodep); } - AstNode* outp() const { return op2p(); } // op2 = Expressions to output - void outp(AstNode* nodep) { setOp2p(nodep); } -}; - -class AstTestPlusArgs final : public AstNodeMath { - // Parents: expr - // Child: variable to set. If nullptr then this is a $test$plusargs instead of $value$plusargs -public: - AstTestPlusArgs(FileLine* fl, AstNode* searchp) - : ASTGEN_SUPER_TestPlusArgs(fl) { - setOp1p(searchp); - } - ASTNODE_NODE_FUNCS(TestPlusArgs) - virtual string verilogKwd() const override { return "$test$plusargs"; } - virtual string emitVerilog() override { return verilogKwd(); } - virtual string emitC() override { return "VL_VALUEPLUSARGS_%nq(%lw, %P, nullptr)"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool cleanOut() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstNode* searchp() const { return op1p(); } // op1 = Search expression - void searchp(AstNode* nodep) { setOp1p(nodep); } -}; - -class AstGenFor final : public AstNodeFor { -public: - AstGenFor(FileLine* fl, AstNode* initsp, AstNode* condp, AstNode* incsp, AstNode* bodysp) - : ASTGEN_SUPER_GenFor(fl, initsp, condp, incsp, bodysp) {} - ASTNODE_NODE_FUNCS(GenFor) -}; - -class AstForeach final : public AstNodeStmt { -public: - AstForeach(FileLine* fl, AstNode* arrayp, AstNode* bodysp) - : ASTGEN_SUPER_Foreach(fl) { - setOp1p(arrayp); - addNOp4p(bodysp); - } - ASTNODE_NODE_FUNCS(Foreach) - AstNode* arrayp() const { return op1p(); } // op1 = array and index vars - AstNode* bodysp() const { return op4p(); } // op4 = body of loop - virtual bool isGateOptimizable() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - bool isFirstInMyListOfStatements(AstNode* n) const override { return n == bodysp(); } -}; - -class AstRepeat final : public AstNodeStmt { -public: - AstRepeat(FileLine* fl, AstNode* countp, AstNode* bodysp) - : ASTGEN_SUPER_Repeat(fl) { - setOp2p(countp); - addNOp3p(bodysp); - } - ASTNODE_NODE_FUNCS(Repeat) - AstNode* countp() const { return op2p(); } // op2 = condition to continue - AstNode* bodysp() const { return op3p(); } // op3 = body of loop - virtual bool isGateOptimizable() const override { - return false; - } // Not relevant - converted to FOR - virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - bool isFirstInMyListOfStatements(AstNode* n) const override { return n == bodysp(); } -}; - -class AstWait final : public AstNodeStmt { -public: - AstWait(FileLine* fl, AstNode* condp, AstNode* bodysp) - : ASTGEN_SUPER_Wait(fl) { - setOp2p(condp); - addNOp3p(bodysp); - } - ASTNODE_NODE_FUNCS(Wait) - AstNode* bodysp() const { return op3p(); } // op3 = body of loop - bool isFirstInMyListOfStatements(AstNode* n) const override { return n == bodysp(); } -}; - -class AstWhile final : public AstNodeStmt { -public: - AstWhile(FileLine* fl, AstNode* condp, AstNode* bodysp = nullptr, AstNode* incsp = nullptr) - : ASTGEN_SUPER_While(fl) { - setOp2p(condp); - addNOp3p(bodysp); - addNOp4p(incsp); - } - ASTNODE_NODE_FUNCS(While) - // op1 = prepare statements for condition (exec every loop) - AstNode* precondsp() const { return op1p(); } - AstNode* condp() const { return op2p(); } // op2 = condition to continue - AstNode* bodysp() const { return op3p(); } // op3 = body of loop - AstNode* incsp() const { return op4p(); } // op4 = increment (if from a FOR loop) - void addPrecondsp(AstNode* newp) { addOp1p(newp); } - void addBodysp(AstNode* newp) { addOp3p(newp); } - void addIncsp(AstNode* newp) { addOp4p(newp); } - virtual bool isGateOptimizable() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - // Stop statement searchback here - virtual void addBeforeStmt(AstNode* newp, AstNode* belowp) override; - // Stop statement searchback here - virtual void addNextStmt(AstNode* newp, AstNode* belowp) override; - bool isFirstInMyListOfStatements(AstNode* n) const override { return n == bodysp(); } -}; - -class AstBreak final : public AstNodeStmt { -public: - explicit AstBreak(FileLine* fl) - : ASTGEN_SUPER_Break(fl) {} - ASTNODE_NODE_FUNCS(Break) - virtual string verilogKwd() const override { return "break"; } - virtual bool isBrancher() const override { - return true; // SPECIAL: We don't process code after breaks - } -}; - -class AstContinue final : public AstNodeStmt { -public: - explicit AstContinue(FileLine* fl) - : ASTGEN_SUPER_Continue(fl) {} - ASTNODE_NODE_FUNCS(Continue) - virtual string verilogKwd() const override { return "continue"; } - virtual bool isBrancher() const override { - return true; // SPECIAL: We don't process code after breaks - } -}; - -class AstDisable final : public AstNodeStmt { -private: - string m_name; // Name of block -public: - AstDisable(FileLine* fl, const string& name) - : ASTGEN_SUPER_Disable(fl) - , m_name{name} {} - ASTNODE_NODE_FUNCS(Disable) - virtual string name() const override { return m_name; } // * = Block name - virtual void name(const string& flag) override { m_name = flag; } - virtual bool isBrancher() const override { - return true; // SPECIAL: We don't process code after breaks - } -}; - -class AstDisableFork final : public AstNodeStmt { - // A "disable fork" statement -public: - explicit AstDisableFork(FileLine* fl) - : ASTGEN_SUPER_DisableFork(fl) {} - ASTNODE_NODE_FUNCS(DisableFork) -}; - -class AstWaitFork final : public AstNodeStmt { - // A "wait fork" statement -public: - explicit AstWaitFork(FileLine* fl) - : ASTGEN_SUPER_WaitFork(fl) {} - ASTNODE_NODE_FUNCS(WaitFork) -}; - -class AstReturn final : public AstNodeStmt { -public: - explicit AstReturn(FileLine* fl, AstNode* lhsp = nullptr) - : ASTGEN_SUPER_Return(fl) { - setNOp1p(lhsp); - } - ASTNODE_NODE_FUNCS(Return) - virtual string verilogKwd() const override { return "return"; } - AstNode* lhsp() const { return op1p(); } - virtual bool isBrancher() const override { - return true; // SPECIAL: We don't process code after breaks - } -}; - -class AstGenIf final : public AstNodeIf { -public: - AstGenIf(FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp) - : ASTGEN_SUPER_GenIf(fl, condp, ifsp, elsesp) {} - ASTNODE_NODE_FUNCS(GenIf) -}; - -class AstIf final : public AstNodeIf { -private: - bool m_uniquePragma; // unique case - bool m_unique0Pragma; // unique0 case - bool m_priorityPragma; // priority case -public: - AstIf(FileLine* fl, AstNode* condp, AstNode* ifsp = nullptr, AstNode* elsesp = nullptr) - : ASTGEN_SUPER_If(fl, condp, ifsp, elsesp) { - m_uniquePragma = false; - m_unique0Pragma = false; - m_priorityPragma = false; - } - ASTNODE_NODE_FUNCS(If) - bool uniquePragma() const { return m_uniquePragma; } - void uniquePragma(bool flag) { m_uniquePragma = flag; } - bool unique0Pragma() const { return m_unique0Pragma; } - void unique0Pragma(bool flag) { m_unique0Pragma = flag; } - bool priorityPragma() const { return m_priorityPragma; } - void priorityPragma(bool flag) { m_priorityPragma = flag; } -}; - -class AstJumpBlock final : public AstNodeStmt { - // Block of code including a JumpGo and JumpLabel - // Parents: {statement list} - // Children: {statement list, with JumpGo and JumpLabel below} -private: - AstJumpLabel* m_labelp = nullptr; // [After V3Jump] Pointer to declaration - int m_labelNum = 0; // Set by V3EmitCSyms to tell final V3Emit what to increment -public: - // After construction must call ->labelp to associate with appropriate label - AstJumpBlock(FileLine* fl, AstNode* stmtsp) - : ASTGEN_SUPER_JumpBlock(fl) { - addNOp1p(stmtsp); - } - virtual const char* broken() const override; - virtual void cloneRelink() override; - ASTNODE_NODE_FUNCS(JumpBlock) - virtual int instrCount() const override { return 0; } - virtual bool maybePointedTo() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - // op1 = Statements - AstNode* stmtsp() const { return op1p(); } // op1 = List of statements - void addStmtsp(AstNode* nodep) { addNOp1p(nodep); } - AstNode* endStmtsp() const { return op2p(); } // op1 = List of end-of-block - void addEndStmtsp(AstNode* nodep) { addNOp2p(nodep); } - int labelNum() const { return m_labelNum; } - void labelNum(int flag) { m_labelNum = flag; } - AstJumpLabel* labelp() const { return m_labelp; } - void labelp(AstJumpLabel* labelp) { m_labelp = labelp; } -}; - -class AstJumpLabel final : public AstNodeStmt { - // Jump point declaration - // Parents: {statement list with JumpBlock above} - // Children: none -private: - AstJumpBlock* m_blockp; // [After V3Jump] Pointer to declaration -public: - AstJumpLabel(FileLine* fl, AstJumpBlock* blockp) - : ASTGEN_SUPER_JumpLabel(fl) - , m_blockp{blockp} {} - ASTNODE_NODE_FUNCS(JumpLabel) - virtual bool maybePointedTo() const override { return true; } - virtual const char* broken() const override { - BROKEN_RTN(!blockp()->brokeExistsAbove()); - BROKEN_RTN(blockp()->labelp() != this); - return nullptr; - } - virtual void cloneRelink() override { - if (m_blockp->clonep()) m_blockp = m_blockp->clonep(); - } - virtual void dump(std::ostream& str) const override; - virtual int instrCount() const override { return 0; } - virtual bool same(const AstNode* samep) const override { - return blockp() == static_cast(samep)->blockp(); - } - AstJumpBlock* blockp() const { return m_blockp; } -}; - -class AstJumpGo final : public AstNodeStmt { - // Jump point; branch down to a JumpLabel - // No support for backward jumps at present - // Parents: {statement list with JumpBlock above} - // Children: none -private: - AstJumpLabel* m_labelp; // [After V3Jump] Pointer to declaration -public: - AstJumpGo(FileLine* fl, AstJumpLabel* labelp) - : ASTGEN_SUPER_JumpGo(fl) - , m_labelp{labelp} {} - ASTNODE_NODE_FUNCS(JumpGo); - virtual const char* broken() const override { - BROKEN_RTN(!labelp()->brokeExistsBelow()); - return nullptr; - } - virtual void cloneRelink() override { - if (m_labelp->clonep()) m_labelp = m_labelp->clonep(); - } - virtual void dump(std::ostream& str) const override; - virtual int instrCount() const override { return INSTR_COUNT_BRANCH; } - virtual bool same(const AstNode* samep) const override { - return labelp() == static_cast(samep)->labelp(); - } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isBrancher() const override { - return true; // SPECIAL: We don't process code after breaks - } - AstJumpLabel* labelp() const { return m_labelp; } -}; - -class AstChangeDet final : public AstNodeStmt { - // A comparison to determine change detection, common & must be fast. -public: - // Null lhs+rhs used to indicate change needed with no spec vars - AstChangeDet(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_ChangeDet(fl) { - setNOp1p(lhsp); - setNOp2p(rhsp); - } - ASTNODE_NODE_FUNCS(ChangeDet) - AstNode* lhsp() const { return op1p(); } - AstNode* rhsp() const { return op2p(); } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 2; } // xor, or/logor - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstConsAssoc final : public AstNodeMath { - // Construct an assoc array and return object, '{} - // Parents: math - // Children: expression (elements or other queues) -public: - AstConsAssoc(FileLine* fl, AstNode* defaultp) - : ASTGEN_SUPER_ConsAssoc(fl) { - setNOp1p(defaultp); - } - ASTNODE_NODE_FUNCS(ConsAssoc) - virtual string emitVerilog() override { return "'{}"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* defaultp() const { return op1p(); } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; -class AstSetAssoc final : public AstNodeMath { - // Set an assoc array element and return object, '{} - // Parents: math - // Children: expression (elements or other queues) -public: - AstSetAssoc(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* valuep) - : ASTGEN_SUPER_SetAssoc(fl) { - setOp1p(lhsp); - setNOp2p(keyp); - setOp3p(valuep); - } - ASTNODE_NODE_FUNCS(SetAssoc) - virtual string emitVerilog() override { return "'{}"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* lhsp() const { return op1p(); } - AstNode* keyp() const { return op2p(); } - AstNode* valuep() const { return op3p(); } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstConsWildcard final : public AstNodeMath { - // Construct a wildcard assoc array and return object, '{} - // Parents: math - // Children: expression (elements or other queues) -public: - AstConsWildcard(FileLine* fl, AstNode* defaultp) - : ASTGEN_SUPER_ConsWildcard(fl) { - setNOp1p(defaultp); - } - ASTNODE_NODE_FUNCS(ConsWildcard) - virtual string emitVerilog() override { return "'{}"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* defaultp() const { return op1p(); } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; -class AstSetWildcard final : public AstNodeMath { - // Set a wildcard assoc array element and return object, '{} - // Parents: math - // Children: expression (elements or other queues) -public: - AstSetWildcard(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* valuep) - : ASTGEN_SUPER_SetWildcard(fl) { - setOp1p(lhsp); - setNOp2p(keyp); - setOp3p(valuep); - } - ASTNODE_NODE_FUNCS(SetWildcard) - virtual string emitVerilog() override { return "'{}"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* lhsp() const { return op1p(); } - AstNode* keyp() const { return op2p(); } - AstNode* valuep() const { return op3p(); } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstConsDynArray final : public AstNodeMath { - // Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs} - // Parents: math - // Children: expression (elements or other queues) -public: - explicit AstConsDynArray(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr) - : ASTGEN_SUPER_ConsDynArray(fl) { - setNOp1p(lhsp); - setNOp2p(rhsp); - } - ASTNODE_NODE_FUNCS(ConsDynArray) - virtual string emitVerilog() override { return "'{%l, %r}"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* lhsp() const { return op1p(); } // op1 = expression - AstNode* rhsp() const { return op2p(); } // op2 = expression - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstConsQueue final : public AstNodeMath { - // Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs} - // Parents: math - // Children: expression (elements or other queues) -public: - explicit AstConsQueue(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr) - : ASTGEN_SUPER_ConsQueue(fl) { - setNOp1p(lhsp); - setNOp2p(rhsp); - } - ASTNODE_NODE_FUNCS(ConsQueue) - virtual string emitVerilog() override { return "'{%l, %r}"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* lhsp() const { return op1p(); } // op1 = expression - AstNode* rhsp() const { return op2p(); } // op2 = expression - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstBegin final : public AstNodeBlock { - // A Begin/end named block, only exists shortly after parsing until linking - // Parents: statement - // Children: statements -private: - bool m_generate; // Underneath a generate - const bool m_implied; // Not inserted by user -public: - // Node that puts name into the output stream - AstBegin(FileLine* fl, const string& name, AstNode* stmtsp, bool generate = false, - bool implied = false) - : ASTGEN_SUPER_Begin(fl, name, stmtsp) - , m_generate{generate} - , m_implied{implied} {} - ASTNODE_NODE_FUNCS(Begin) - virtual void dump(std::ostream& str) const override; - // op1p is statements in NodeBlock - AstNode* genforp() const { return op2p(); } // op2 = GENFOR, if applicable, - // might NOT be a GenFor, as loop unrolling replaces with Begin - void addGenforp(AstGenFor* nodep) { addOp2p(nodep); } - void generate(bool flag) { m_generate = flag; } - bool generate() const { return m_generate; } - bool implied() const { return m_implied; } -}; - -class AstFork final : public AstNodeBlock { - // A fork named block - // Parents: statement - // Children: statements -private: - VJoinType m_joinType; // Join keyword type -public: - // Node that puts name into the output stream - AstFork(FileLine* fl, const string& name, AstNode* stmtsp) - : ASTGEN_SUPER_Fork(fl, name, stmtsp) {} - ASTNODE_NODE_FUNCS(Fork) - virtual void dump(std::ostream& str) const override; - VJoinType joinType() const { return m_joinType; } - void joinType(const VJoinType& flag) { m_joinType = flag; } -}; - -class AstInside final : public AstNodeMath { -public: - AstInside(FileLine* fl, AstNode* exprp, AstNode* itemsp) - : ASTGEN_SUPER_Inside(fl) { - addOp1p(exprp); - addOp2p(itemsp); - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(Inside) - AstNode* exprp() const { return op1p(); } // op1 = LHS expression to compare with - // op2 = RHS, possibly a list of expr or AstInsideRange - AstNode* itemsp() const { return op2p(); } - virtual string emitVerilog() override { return "%l inside { %r }"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } // NA -}; - -class AstInsideRange final : public AstNodeMath { -public: - AstInsideRange(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_InsideRange(fl) { - addOp1p(lhsp); - addOp2p(rhsp); - } - ASTNODE_NODE_FUNCS(InsideRange) - AstNode* lhsp() const { return op1p(); } // op1 = LHS - AstNode* rhsp() const { return op2p(); } // op2 = RHS - virtual string emitVerilog() override { return "[%l:%r]"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } // NA - // Create AstAnd(AstGte(...), AstLte(...)) - AstNode* newAndFromInside(AstNode* exprp, AstNode* lhsp, AstNode* rhsp); -}; - -class AstInitItem final : public AstNode { - // Container for a item in an init array - // This container is present so that the value underneath may get replaced with a new nodep - // and the upper AstInitArray's map will remain correct (pointing to this InitItem) -public: - // Parents: INITARRAY - AstInitItem(FileLine* fl, AstNode* valuep) - : ASTGEN_SUPER_InitItem(fl) { - addOp1p(valuep); - } - ASTNODE_NODE_FUNCS(InitItem) - virtual bool maybePointedTo() const override { return true; } - virtual bool hasDType() const override { return false; } // See valuep()'s dtype instead - AstNode* valuep() const { return op1p(); } // op1 = Value - void valuep(AstNode* nodep) { addOp1p(nodep); } -}; - -class AstInitArray final : public AstNode { - // Set a var to a map of values - // The list of initsp() is not relevant - // If default is specified, the vector may be sparse, and not provide each value. - // Key values are C++ array style, with lo() at index 0 - // Parents: ASTVAR::init() - // Children: AstInitItem -public: - using KeyItemMap = std::map; - -private: - KeyItemMap m_map; // Node value for each array index -public: - AstInitArray(FileLine* fl, AstNodeDType* newDTypep, AstNode* defaultp) - : ASTGEN_SUPER_InitArray(fl) { - dtypep(newDTypep); - addNOp1p(defaultp); - } - ASTNODE_NODE_FUNCS(InitArray) - virtual void dump(std::ostream& str) const override; - virtual const char* broken() const override { - for (KeyItemMap::const_iterator it = m_map.begin(); it != m_map.end(); ++it) { - BROKEN_RTN(!it->second); - BROKEN_RTN(!it->second->brokeExists()); - } - return nullptr; - } - virtual void cloneRelink() override { - for (KeyItemMap::iterator it = m_map.begin(); it != m_map.end(); ++it) { - if (it->second->clonep()) it->second = it->second->clonep(); - } - } - virtual bool hasDType() const override { return true; } - virtual bool same(const AstNode* samep) const override { - // Only works if exact same children, instead should override comparison - // of children list, and instead use map-vs-map key/value compare - return m_map == static_cast(samep)->m_map; - } - AstNode* defaultp() const { return op1p(); } // op1 = Default if sparse - void defaultp(AstNode* newp) { setOp1p(newp); } - AstNode* initsp() const { return op2p(); } // op2 = Initial value expressions - void addValuep(AstNode* newp) { addIndexValuep(m_map.size(), newp); } - const KeyItemMap& map() const { return m_map; } - AstNode* addIndexValuep(uint64_t index, AstNode* newp) { - // Returns old value, caller must garbage collect - AstNode* oldp = nullptr; - const auto it = m_map.find(index); - if (it != m_map.end()) { - oldp = it->second->valuep(); - it->second->valuep(newp); - } else { - AstInitItem* const itemp = new AstInitItem(fileline(), newp); - m_map.emplace(index, itemp); - addOp2p(itemp); - } - return oldp; - } - AstNode* getIndexValuep(uint64_t index) const { - const auto it = m_map.find(index); - if (it == m_map.end()) { - return nullptr; - } else { - return it->second->valuep(); - } - } - AstNode* getIndexDefaultedValuep(uint64_t index) const { - AstNode* valuep = getIndexValuep(index); - if (!valuep) valuep = defaultp(); - return valuep; - } -}; - -class AstNew final : public AstNodeFTaskRef { - // New as constructor - // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it - // Parents: math|stmt - // Children: varref|arraysel, math -public: - AstNew(FileLine* fl, AstNode* pinsp) - : ASTGEN_SUPER_New(fl, false, "new", pinsp) {} - ASTNODE_NODE_FUNCS(New) - virtual bool cleanOut() const { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual bool hasDType() const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } -}; - -class AstNewCopy final : public AstNodeMath { - // New as shallow copy - // Parents: math|stmt - // Children: varref|arraysel, math -public: - AstNewCopy(FileLine* fl, AstNode* rhsp) - : ASTGEN_SUPER_NewCopy(fl) { - dtypeFrom(rhsp); // otherwise V3Width will resolve - setNOp1p(rhsp); - } - ASTNODE_NODE_FUNCS(NewCopy) - virtual string emitVerilog() override { return "new"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* rhsp() const { return op1p(); } -}; - -class AstNewDynamic final : public AstNodeMath { - // New for dynamic array - // Parents: math|stmt - // Children: varref|arraysel, math -public: - AstNewDynamic(FileLine* fl, AstNode* sizep, AstNode* rhsp) - : ASTGEN_SUPER_NewDynamic(fl) { - dtypeFrom(rhsp); // otherwise V3Width will resolve - setNOp1p(sizep); - setNOp2p(rhsp); - } - ASTNODE_NODE_FUNCS(NewDynamic) - virtual string emitVerilog() override { return "new"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* sizep() const { return op1p(); } - AstNode* rhsp() const { return op2p(); } -}; - -class AstPragma final : public AstNode { -private: - const VPragmaType m_pragType; // Type of pragma -public: - // Pragmas don't result in any output code, they're just flags that affect - // other processing in verilator. - AstPragma(FileLine* fl, VPragmaType pragType) - : ASTGEN_SUPER_Pragma(fl) - , m_pragType{pragType} {} - ASTNODE_NODE_FUNCS(Pragma) - VPragmaType pragType() const { return m_pragType; } // *=type of the pragma - virtual bool isPredictOptimizable() const override { return false; } - virtual bool same(const AstNode* samep) const override { - return pragType() == static_cast(samep)->pragType(); - } -}; - -class AstPrintTimeScale final : public AstNodeStmt { - // Parents: stmtlist - string m_name; // Parent module name - VTimescale m_timeunit; // Parent module time unit -public: - explicit AstPrintTimeScale(FileLine* fl) - : ASTGEN_SUPER_PrintTimeScale(fl) {} - ASTNODE_NODE_FUNCS(PrintTimeScale) - virtual void name(const string& name) override { m_name = name; } - virtual string name() const override { return m_name; } // * = Var name - virtual void dump(std::ostream& str) const override; - virtual string verilogKwd() const override { return "$printtimescale"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual int instrCount() const override { return INSTR_COUNT_PLI; } - void timeunit(const VTimescale& flag) { m_timeunit = flag; } - VTimescale timeunit() const { return m_timeunit; } -}; - -class AstStop final : public AstNodeStmt { -public: - AstStop(FileLine* fl, bool maybe) - : ASTGEN_SUPER_Stop(fl) {} - ASTNODE_NODE_FUNCS(Stop) - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { - return false; - } // SPECIAL: $display has 'visual' ordering - virtual bool isOutputter() const override { return true; } // SPECIAL: $display makes output - virtual bool isUnlikely() const override { return true; } - virtual int instrCount() const override { return 0; } // Rarely executes - virtual bool same(const AstNode* samep) const override { - return fileline() == samep->fileline(); - } -}; - -class AstFinish final : public AstNodeStmt { -public: - explicit AstFinish(FileLine* fl) - : ASTGEN_SUPER_Finish(fl) {} - ASTNODE_NODE_FUNCS(Finish) - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { - return false; - } // SPECIAL: $display has 'visual' ordering - virtual bool isOutputter() const override { return true; } // SPECIAL: $display makes output - virtual bool isUnlikely() const override { return true; } - virtual int instrCount() const override { return 0; } // Rarely executes - virtual bool same(const AstNode* samep) const override { - return fileline() == samep->fileline(); - } -}; - -class AstNullCheck final : public AstNodeUniop { - // Return LHS after checking that LHS is non-null - // Children: VarRef or something returning pointer -public: - AstNullCheck(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_NullCheck(fl, lhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(NullCheck) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } - virtual int instrCount() const override { return 1; } // Rarely executes - virtual string emitVerilog() override { return "%l"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool same(const AstNode* samep) const override { - return fileline() == samep->fileline(); - } -}; - -class AstEventControl final : public AstNodeStmt { - // Parents: stmtlist -public: - AstEventControl(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp) - : ASTGEN_SUPER_EventControl(fl) { - setNOp1p(sensesp); - setNOp2p(stmtsp); - } - ASTNODE_NODE_FUNCS(EventControl) - virtual string verilogKwd() const override { return "@(%l) %r"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return false; } - virtual int instrCount() const override { return 0; } - AstSenTree* sensesp() const { return VN_AS(op1p(), SenTree); } - AstNode* stmtsp() const { return op2p(); } -}; - -class AstTimeFormat final : public AstNodeStmt { - // Parents: stmtlist -public: - AstTimeFormat(FileLine* fl, AstNode* unitsp, AstNode* precisionp, AstNode* suffixp, - AstNode* widthp) - : ASTGEN_SUPER_TimeFormat(fl) { - setOp1p(unitsp); - setOp2p(precisionp); - setOp3p(suffixp); - setOp4p(widthp); - } - ASTNODE_NODE_FUNCS(TimeFormat) - virtual string verilogKwd() const override { return "$timeformat"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual int instrCount() const override { return INSTR_COUNT_PLI; } - AstNode* unitsp() const { return op1p(); } - AstNode* precisionp() const { return op2p(); } - AstNode* suffixp() const { return op3p(); } - AstNode* widthp() const { return op4p(); } -}; - -class AstTracePushNamePrefix final : public AstNodeStmt { - const string m_prefix; // Prefix to add to signal names -public: - AstTracePushNamePrefix(FileLine* fl, const string& prefix) - : ASTGEN_SUPER_TracePushNamePrefix(fl) - , m_prefix{prefix} {} - ASTNODE_NODE_FUNCS(TracePushNamePrefix) - virtual bool same(const AstNode* samep) const override { return false; } - string prefix() const { return m_prefix; } -}; - -class AstTracePopNamePrefix final : public AstNodeStmt { - const unsigned m_count; // How many levels to pop -public: - AstTracePopNamePrefix(FileLine* fl, unsigned count) - : ASTGEN_SUPER_TracePopNamePrefix(fl) - , m_count{count} {} - ASTNODE_NODE_FUNCS(TracePopNamePrefix) - virtual bool same(const AstNode* samep) const override { return false; } - unsigned count() const { return m_count; } -}; - -class AstTraceDecl final : public AstNodeStmt { - // Trace point declaration - // Separate from AstTraceInc; as a declaration can't be deleted - // Parents: {statement list} - // Children: expression being traced -private: - uint32_t m_code = 0; // Trace identifier code; converted to ASCII by trace routines - const string m_showname; // Name of variable - const VNumRange m_bitRange; // Property of var the trace details - const VNumRange m_arrayRange; // Property of var the trace details - const uint32_t m_codeInc; // Code increment - const VVarType m_varType; // Type of variable (for localparam vs. param) - const VBasicDTypeKwd m_declKwd; // Keyword at declaration time - const VDirection m_declDirection; // Declared direction input/output etc -public: - AstTraceDecl(FileLine* fl, const string& showname, - AstVar* varp, // For input/output state etc - AstNode* valuep, const VNumRange& bitRange, const VNumRange& arrayRange) - : ASTGEN_SUPER_TraceDecl(fl) - , m_showname{showname} - , m_bitRange{bitRange} - , m_arrayRange{arrayRange} - , m_codeInc( - ((arrayRange.ranged() ? arrayRange.elements() : 1) * valuep->dtypep()->widthWords() - * (VL_EDATASIZE / 32))) // A code is always 32-bits - , m_varType{varp->varType()} - , m_declKwd{varp->declKwd()} - , m_declDirection{varp->declDirection()} { - dtypeFrom(valuep); - addNOp1p(valuep); - } - virtual void dump(std::ostream& str) const override; - virtual int instrCount() const override { return 100; } // Large... - ASTNODE_NODE_FUNCS(TraceDecl) - virtual string name() const override { return m_showname; } - virtual bool maybePointedTo() const override { return true; } - virtual bool hasDType() const override { return true; } - virtual bool same(const AstNode* samep) const override { return false; } - string showname() const { return m_showname; } // * = Var name - // Details on what we're tracing - uint32_t code() const { return m_code; } - void code(uint32_t code) { m_code = code; } - uint32_t codeInc() const { return m_codeInc; } - const VNumRange& bitRange() const { return m_bitRange; } - const VNumRange& arrayRange() const { return m_arrayRange; } - VVarType varType() const { return m_varType; } - VBasicDTypeKwd declKwd() const { return m_declKwd; } - VDirection declDirection() const { return m_declDirection; } - AstNode* valuep() const { return op1p(); } -}; - -class AstTraceInc final : public AstNodeStmt { - // Trace point dump - // Parents: {statement list} - // Children: op1: things to emit before this node, - // op2: expression being traced (from decl) - -private: - AstTraceDecl* m_declp; // Pointer to declaration - const bool m_full; // Is this a full vs incremental dump - const uint32_t m_baseCode; // Trace code base value in function containing this AstTraceInc - -public: - AstTraceInc(FileLine* fl, AstTraceDecl* declp, bool full, uint32_t baseCode = 0) - : ASTGEN_SUPER_TraceInc(fl) - , m_declp{declp} - , m_full{full} - , m_baseCode{baseCode} { - dtypeFrom(declp); - addOp2p(declp->valuep()->cloneTree(true)); - } - ASTNODE_NODE_FUNCS(TraceInc) - virtual const char* broken() const override { - BROKEN_RTN(!declp()->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { - if (m_declp->clonep()) m_declp = m_declp->clonep(); - } - virtual void dump(std::ostream& str) const override; - virtual int instrCount() const override { return 10 + 2 * INSTR_COUNT_LD; } - virtual bool hasDType() const override { return true; } - virtual bool same(const AstNode* samep) const override { - return declp() == static_cast(samep)->declp(); - } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isOutputter() const override { return true; } - // but isPure() true - // op1 = Statements before the value - AstNode* precondsp() const { return op1p(); } - void addPrecondsp(AstNode* newp) { addOp1p(newp); } - AstNode* valuep() const { return op2p(); } - AstTraceDecl* declp() const { return m_declp; } - bool full() const { return m_full; } - uint32_t baseCode() const { return m_baseCode; } -}; - -class AstActive final : public AstNode { - // Block of code with sensitivity activation - // Parents: MODULE | CFUNC - // Children: SENTREE, statements -private: - string m_name; - AstSenTree* m_sensesp; - -public: - AstActive(FileLine* fl, const string& name, AstSenTree* sensesp) - : ASTGEN_SUPER_Active(fl) { - m_name = name; // Copy it - UASSERT(sensesp, "Sensesp required arg"); - m_sensesp = sensesp; - } - ASTNODE_NODE_FUNCS(Active) - virtual void dump(std::ostream& str = std::cout) const override; - virtual string name() const override { return m_name; } - virtual const char* broken() const override { - BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { - if (m_sensesp->clonep()) { - m_sensesp = m_sensesp->clonep(); - UASSERT(m_sensesp, "Bad clone cross link: " << this); - } - } - // Statements are broken into pieces, as some must come before others. - void sensesp(AstSenTree* nodep) { m_sensesp = nodep; } - AstSenTree* sensesp() const { return m_sensesp; } - // op1 = Sensitivity tree, if a clocked block in early stages - void sensesStorep(AstSenTree* nodep) { addOp1p(nodep); } - AstSenTree* sensesStorep() const { return VN_AS(op1p(), SenTree); } - // op2 = Combo logic - AstNode* stmtsp() const { return op2p(); } - void addStmtsp(AstNode* nodep) { addOp2p(nodep); } - // METHODS - bool hasInitial() const { return m_sensesp->hasInitial(); } - bool hasSettle() const { return m_sensesp->hasSettle(); } - bool hasClocked() const { return m_sensesp->hasClocked(); } -}; - -class AstAttrOf final : public AstNode { -private: - // Return a value of a attribute, for example a LSB or array LSB of a signal - VAttrType m_attrType; // What sort of extraction -public: - AstAttrOf(FileLine* fl, VAttrType attrtype, AstNode* fromp = nullptr, AstNode* dimp = nullptr) - : ASTGEN_SUPER_AttrOf(fl) { - setNOp1p(fromp); - setNOp2p(dimp); - m_attrType = attrtype; - } - ASTNODE_NODE_FUNCS(AttrOf) - AstNode* fromp() const { return op1p(); } - AstNode* dimp() const { return op2p(); } - VAttrType attrType() const { return m_attrType; } - virtual void dump(std::ostream& str = std::cout) const override; -}; - -class AstScopeName final : public AstNodeMath { - // For display %m and DPI context imports - // Parents: DISPLAY - // Children: TEXT -private: - bool m_dpiExport = false; // Is for dpiExport - const bool m_forFormat = false; // Is for a format %m - string scopeNameFormatter(AstText* scopeTextp) const; - string scopePrettyNameFormatter(AstText* scopeTextp) const; - -public: - class ForFormat {}; - AstScopeName(FileLine* fl, bool forFormat) - : ASTGEN_SUPER_ScopeName(fl) - , m_forFormat{forFormat} { - dtypeSetUInt64(); - } - ASTNODE_NODE_FUNCS(ScopeName) - virtual bool same(const AstNode* samep) const override { - return (m_dpiExport == static_cast(samep)->m_dpiExport - && m_forFormat == static_cast(samep)->m_forFormat); - } - virtual string emitVerilog() override { return ""; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual void dump(std::ostream& str = std::cout) const override; - AstText* scopeAttrp() const { return VN_AS(op1p(), Text); } - void scopeAttrp(AstNode* nodep) { addOp1p(nodep); } - AstText* scopeEntrp() const { return VN_AS(op2p(), Text); } - void scopeEntrp(AstNode* nodep) { addOp2p(nodep); } - string scopeSymName() const { // Name for __Vscope variable including children - return scopeNameFormatter(scopeAttrp()); - } - string scopeDpiName() const { // Name for DPI import scope - return scopeNameFormatter(scopeEntrp()); - } - string scopePrettySymName() const { // Name for __Vscope variable including children - return scopePrettyNameFormatter(scopeAttrp()); - } - string scopePrettyDpiName() const { // Name for __Vscope variable including children - return scopePrettyNameFormatter(scopeEntrp()); - } - bool dpiExport() const { return m_dpiExport; } - void dpiExport(bool flag) { m_dpiExport = flag; } - bool forFormat() const { return m_forFormat; } -}; - -class AstUdpTable final : public AstNode { -public: - AstUdpTable(FileLine* fl, AstNode* bodysp) - : ASTGEN_SUPER_UdpTable(fl) { - addNOp1p(bodysp); - } - ASTNODE_NODE_FUNCS(UdpTable) - // op1 = List of UdpTableLines - AstUdpTableLine* bodysp() const { return VN_AS(op1p(), UdpTableLine); } -}; - -class AstUdpTableLine final : public AstNode { - string m_text; - -public: - AstUdpTableLine(FileLine* fl, const string& text) - : ASTGEN_SUPER_UdpTableLine(fl) - , m_text{text} {} - ASTNODE_NODE_FUNCS(UdpTableLine) - virtual string name() const override { return m_text; } - string text() const { return m_text; } -}; - -//====================================================================== -// non-ary ops - -class AstRand final : public AstNodeMath { - // $random/$random(seed) or $urandom/$urandom(seed) - // Return a random number, based upon width() -private: - const bool m_urandom = false; // $urandom vs $random - const bool m_reset = false; // Random reset, versus always random -public: - class Reset {}; - AstRand(FileLine* fl, Reset, AstNodeDType* dtp, bool reset) - : ASTGEN_SUPER_Rand(fl) - , m_reset{reset} { - dtypep(dtp); - } - AstRand(FileLine* fl, AstNode* seedp, bool urandom) - : ASTGEN_SUPER_Rand(fl) - , m_urandom(urandom) { - setNOp1p(seedp); - } - ASTNODE_NODE_FUNCS(Rand) - virtual string emitVerilog() override { - return seedp() ? (m_urandom ? "%f$urandom(%l)" : "%f$random(%l)") - : (m_urandom ? "%f$urandom()" : "%f$random()"); - } - virtual string emitC() override { - return m_reset ? "VL_RAND_RESET_%nq(%nw, %P)" - : seedp() - ? (urandom() ? "VL_URANDOM_SEEDED_%nq%lq(%li)" : "VL_RANDOM_SEEDED_%nq%lq(%li)") - : isWide() ? "VL_RANDOM_%nq(%nw, %P)" // - : "VL_RANDOM_%nq()"; - } - virtual bool cleanOut() const override { return false; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_PLI; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - bool combinable(const AstRand* samep) const { - return !seedp() && !samep->seedp() && reset() == samep->reset() - && urandom() == samep->urandom(); - } - AstNode* seedp() const { return op1p(); } - bool reset() const { return m_reset; } - bool urandom() const { return m_urandom; } -}; - -class AstURandomRange final : public AstNodeBiop { - // $urandom_range -public: - explicit AstURandomRange(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_URandomRange(fl, lhsp, rhsp) { - dtypeSetUInt32(); // Says IEEE - } - ASTNODE_NODE_FUNCS(URandomRange) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstURandomRange(fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - V3ERROR_NA; - } - virtual string emitVerilog() override { return "%f$urandom_range(%l, %r)"; } - virtual string emitC() override { return "VL_URANDOM_RANGE_%nq(%li, %ri)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_PLI; } -}; - -class AstTime final : public AstNodeTermop { - VTimescale m_timeunit; // Parent module time unit -public: - AstTime(FileLine* fl, const VTimescale& timeunit) - : ASTGEN_SUPER_Time(fl) - , m_timeunit{timeunit} { - dtypeSetUInt64(); - } - ASTNODE_NODE_FUNCS(Time) - virtual string emitVerilog() override { return "%f$time"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_TIME; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual void dump(std::ostream& str = std::cout) const override; - void timeunit(const VTimescale& flag) { m_timeunit = flag; } - VTimescale timeunit() const { return m_timeunit; } -}; - -class AstTimeD final : public AstNodeTermop { - VTimescale m_timeunit; // Parent module time unit -public: - AstTimeD(FileLine* fl, const VTimescale& timeunit) - : ASTGEN_SUPER_TimeD(fl) - , m_timeunit{timeunit} { - dtypeSetDouble(); - } - ASTNODE_NODE_FUNCS(TimeD) - virtual string emitVerilog() override { return "%f$realtime"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_TIME; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - virtual void dump(std::ostream& str = std::cout) const override; - void timeunit(const VTimescale& flag) { m_timeunit = flag; } - VTimescale timeunit() const { return m_timeunit; } -}; - -class AstUCFunc final : public AstNodeMath { - // User's $c function - // Perhaps this should be an AstNodeListop; but there's only one list math right now -public: - AstUCFunc(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER_UCFunc(fl) { - addNOp1p(exprsp); - } - ASTNODE_NODE_FUNCS(UCFunc) - virtual bool cleanOut() const override { return false; } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - AstNode* bodysp() const { return op1p(); } // op1 = expressions to print - virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs - virtual bool isOutputter() const override { return true; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isSubstOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_PLI; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -//====================================================================== -// Unary ops - -class AstNegate final : public AstNodeUniop { -public: - AstNegate(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_Negate(fl, lhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(Negate) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNegate(lhs); } - virtual string emitVerilog() override { return "%f(- %l)"; } - virtual string emitC() override { return "VL_NEGATE_%lq(%lW, %P, %li)"; } - virtual string emitSimpleOperator() override { return "-"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return true; } -}; -class AstNegateD final : public AstNodeUniop { -public: - AstNegateD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_NegateD(fl, lhsp) { - dtypeSetDouble(); - } - ASTNODE_NODE_FUNCS(NegateD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNegateD(lhs); } - virtual string emitVerilog() override { return "%f(- %l)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "-"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstRedAnd final : public AstNodeUniop { -public: - AstRedAnd(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_RedAnd(fl, lhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(RedAnd) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedAnd(lhs); } - virtual string emitVerilog() override { return "%f(& %l)"; } - virtual string emitC() override { return "VL_REDAND_%nq%lq(%lw, %P, %li)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } -}; -class AstRedOr final : public AstNodeUniop { -public: - AstRedOr(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_RedOr(fl, lhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(RedOr) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedOr(lhs); } - virtual string emitVerilog() override { return "%f(| %l)"; } - virtual string emitC() override { return "VL_REDOR_%lq(%lW, %P, %li)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } -}; -class AstRedXor final : public AstNodeUniop { -public: - AstRedXor(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_RedXor(fl, lhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(RedXor) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedXor(lhs); } - virtual string emitVerilog() override { return "%f(^ %l)"; } - virtual string emitC() override { return "VL_REDXOR_%lq(%lW, %P, %li)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { - const int w = lhsp()->width(); - return (w != 1 && w != 2 && w != 4 && w != 8 && w != 16); - } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return 1 + V3Number::log2b(width()); } -}; - -class AstLenN final : public AstNodeUniop { - // Length of a string -public: - AstLenN(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_LenN(fl, lhsp) { - dtypeSetSigned32(); - } - ASTNODE_NODE_FUNCS(LenN) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opLenN(lhs); } - virtual string emitVerilog() override { return "%f(%l)"; } - virtual string emitC() override { return "VL_LEN_IN(%li)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } -}; -class AstLogNot final : public AstNodeUniop { -public: - AstLogNot(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_LogNot(fl, lhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(LogNot) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opLogNot(lhs); } - virtual string emitVerilog() override { return "%f(! %l)"; } - virtual string emitC() override { return "VL_LOGNOT_%nq%lq(%nw,%lw, %P, %li)"; } - virtual string emitSimpleOperator() override { return "!"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } -}; -class AstNot final : public AstNodeUniop { -public: - AstNot(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_Not(fl, lhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(Not) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNot(lhs); } - virtual string emitVerilog() override { return "%f(~ %l)"; } - virtual string emitC() override { return "VL_NOT_%lq(%lW, %P, %li)"; } - virtual string emitSimpleOperator() override { return "~"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return true; } -}; -class AstExtend final : public AstNodeUniop { - // Expand a value into a wider entity by 0 extension. Width is implied from nodep->width() -public: - AstExtend(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_Extend(fl, lhsp) {} - AstExtend(FileLine* fl, AstNode* lhsp, int width) - : ASTGEN_SUPER_Extend(fl, lhsp) { - dtypeSetLogicSized(width, VSigning::UNSIGNED); - } - ASTNODE_NODE_FUNCS(Extend) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAssign(lhs); } - virtual string emitVerilog() override { return "%l"; } - virtual string emitC() override { return "VL_EXTEND_%nq%lq(%nw,%lw, %P, %li)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { - return false; // Because the EXTEND operator self-casts - } - virtual int instrCount() const override { return 0; } -}; -class AstExtendS final : public AstNodeUniop { - // Expand a value into a wider entity by sign extension. Width is implied from nodep->width() -public: - AstExtendS(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_ExtendS(fl, lhsp) {} - AstExtendS(FileLine* fl, AstNode* lhsp, int width) - // Important that widthMin be correct, as opExtend requires it after V3Expand - : ASTGEN_SUPER_ExtendS(fl, lhsp) { - dtypeSetLogicSized(width, VSigning::UNSIGNED); - } - ASTNODE_NODE_FUNCS(ExtendS) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.opExtendS(lhs, lhsp()->widthMinV()); - } - virtual string emitVerilog() override { return "%l"; } - virtual string emitC() override { return "VL_EXTENDS_%nq%lq(%nw,%lw, %P, %li)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { - return false; // Because the EXTEND operator self-casts - } - virtual int instrCount() const override { return 0; } - virtual bool signedFlavor() const override { return true; } -}; -class AstSigned final : public AstNodeUniop { - // $signed(lhs) -public: - AstSigned(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_Signed(fl, lhsp) { - UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, - "not coded to create after dtypes resolved"); - } - ASTNODE_NODE_FUNCS(Signed) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.opAssign(lhs); - out.isSigned(false); - } - virtual string emitVerilog() override { return "%f$signed(%l)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } // Eliminated before matters - virtual bool sizeMattersLhs() const override { return true; } // Eliminated before matters - virtual int instrCount() const override { return 0; } -}; -class AstUnsigned final : public AstNodeUniop { - // $unsigned(lhs) -public: - AstUnsigned(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_Unsigned(fl, lhsp) { - UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, - "not coded to create after dtypes resolved"); - } - ASTNODE_NODE_FUNCS(Unsigned) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.opAssign(lhs); - out.isSigned(false); - } - virtual string emitVerilog() override { return "%f$unsigned(%l)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } // Eliminated before matters - virtual bool sizeMattersLhs() const override { return true; } // Eliminated before matters - virtual int instrCount() const override { return 0; } -}; -class AstRToIS final : public AstNodeUniop { - // $rtoi(lhs) -public: - AstRToIS(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_RToIS(fl, lhsp) { - dtypeSetSigned32(); - } - ASTNODE_NODE_FUNCS(RToIS) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRToIS(lhs); } - virtual string emitVerilog() override { return "%f$rtoi(%l)"; } - virtual string emitC() override { return "VL_RTOI_I_D(%li)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } // Eliminated before matters - virtual bool sizeMattersLhs() const override { return false; } // Eliminated before matters - virtual int instrCount() const override { return INSTR_COUNT_DBL; } -}; -class AstRToIRoundS final : public AstNodeUniop { - // Convert real to integer, with arbitrary sized output (not just "integer" format) -public: - AstRToIRoundS(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_RToIRoundS(fl, lhsp) { - dtypeSetSigned32(); - } - ASTNODE_NODE_FUNCS(RToIRoundS) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.opRToIRoundS(lhs); - } - virtual string emitVerilog() override { return "%f$rtoi_rounded(%l)"; } - virtual string emitC() override { - return isWide() ? "VL_RTOIROUND_%nq_D(%nw, %P, %li)" : "VL_RTOIROUND_%nq_D(%li)"; - } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } -}; -class AstIToRD final : public AstNodeUniop { - // $itor where lhs is unsigned -public: - AstIToRD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_IToRD(fl, lhsp) { - dtypeSetDouble(); - } - ASTNODE_NODE_FUNCS(IToRD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opIToRD(lhs); } - virtual string emitVerilog() override { return "%f$itor(%l)"; } - virtual string emitC() override { return "VL_ITOR_D_%lq(%lw, %li)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } -}; -class AstISToRD final : public AstNodeUniop { - // $itor where lhs is signed -public: - AstISToRD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_ISToRD(fl, lhsp) { - dtypeSetDouble(); - } - ASTNODE_NODE_FUNCS(ISToRD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opISToRD(lhs); } - virtual string emitVerilog() override { return "%f$itor($signed(%l))"; } - virtual string emitC() override { return "VL_ISTOR_D_%lq(%lw, %li)"; } - virtual bool emitCheckMaxWords() override { return true; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } -}; -class AstRealToBits final : public AstNodeUniop { -public: - AstRealToBits(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_RealToBits(fl, lhsp) { - dtypeSetUInt64(); - } - ASTNODE_NODE_FUNCS(RealToBits) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.opRealToBits(lhs); - } - virtual string emitVerilog() override { return "%f$realtobits(%l)"; } - virtual string emitC() override { return "VL_CVT_Q_D(%li)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } // Eliminated before matters - virtual bool sizeMattersLhs() const override { return false; } // Eliminated before matters - virtual int instrCount() const override { return INSTR_COUNT_DBL; } -}; -class AstBitsToRealD final : public AstNodeUniop { -public: - AstBitsToRealD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_BitsToRealD(fl, lhsp) { - dtypeSetDouble(); - } - ASTNODE_NODE_FUNCS(BitsToRealD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.opBitsToRealD(lhs); - } - virtual string emitVerilog() override { return "%f$bitstoreal(%l)"; } - virtual string emitC() override { return "VL_CVT_D_Q(%li)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } // Eliminated before matters - virtual bool sizeMattersLhs() const override { return false; } // Eliminated before matters - virtual int instrCount() const override { return INSTR_COUNT_DBL; } -}; - -class AstCLog2 final : public AstNodeUniop { -public: - AstCLog2(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_CLog2(fl, lhsp) { - dtypeSetSigned32(); - } - ASTNODE_NODE_FUNCS(CLog2) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opCLog2(lhs); } - virtual string emitVerilog() override { return "%f$clog2(%l)"; } - virtual string emitC() override { return "VL_CLOG2_%lq(%lW, %P, %li)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 16; } -}; -class AstCountBits final : public AstNodeQuadop { - // Number of bits set in vector -public: - AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p) - : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl1p->cloneTree(false), - ctrl1p->cloneTree(false)) {} - AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p, AstNode* ctrl2p) - : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl2p->cloneTree(false)) {} - AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p, AstNode* ctrl2p, AstNode* ctrl3p) - : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl3p) {} - ASTNODE_NODE_FUNCS(CountBits) - virtual void numberOperate(V3Number& out, const V3Number& expr, const V3Number& ctrl1, - const V3Number& ctrl2, const V3Number& ctrl3) override { - out.opCountBits(expr, ctrl1, ctrl2, ctrl3); - } - virtual string emitVerilog() override { return "%f$countbits(%l, %r, %f, %o)"; } - virtual string emitC() override { return ""; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool cleanThs() const override { return true; } - virtual bool cleanFhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool sizeMattersThs() const override { return false; } - virtual bool sizeMattersFhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 16; } -}; -class AstCountOnes final : public AstNodeUniop { - // Number of bits set in vector -public: - AstCountOnes(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_CountOnes(fl, lhsp) {} - ASTNODE_NODE_FUNCS(CountOnes) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.opCountOnes(lhs); - } - virtual string emitVerilog() override { return "%f$countones(%l)"; } - virtual string emitC() override { return "VL_COUNTONES_%lq(%lW, %P, %li)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 16; } -}; -class AstIsUnknown final : public AstNodeUniop { - // True if any unknown bits -public: - AstIsUnknown(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_IsUnknown(fl, lhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(IsUnknown) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.opIsUnknown(lhs); - } - virtual string emitVerilog() override { return "%f$isunknown(%l)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } -}; -class AstIsUnbounded final : public AstNodeUniop { - // True if is unmbounded ($) -public: - AstIsUnbounded(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_IsUnbounded(fl, lhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(IsUnbounded) - virtual void numberOperate(V3Number& out, const V3Number&) override { - // Any constant isn't unbounded - out.setZero(); - } - virtual string emitVerilog() override { return "%f$isunbounded(%l)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } -}; -class AstOneHot final : public AstNodeUniop { - // True if only single bit set in vector -public: - AstOneHot(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_OneHot(fl, lhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(OneHot) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opOneHot(lhs); } - virtual string emitVerilog() override { return "%f$onehot(%l)"; } - virtual string emitC() override { return "VL_ONEHOT_%lq(%lW, %P, %li)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 4; } -}; -class AstOneHot0 final : public AstNodeUniop { - // True if only single bit, or no bits set in vector -public: - AstOneHot0(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_OneHot0(fl, lhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(OneHot0) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opOneHot0(lhs); } - virtual string emitVerilog() override { return "%f$onehot0(%l)"; } - virtual string emitC() override { return "VL_ONEHOT0_%lq(%lW, %P, %li)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 3; } -}; - -class AstCast final : public AstNode { - // Cast to appropriate data type - note lhsp is value, to match AstTypedef, AstCCast, etc -public: - AstCast(FileLine* fl, AstNode* lhsp, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER_Cast(fl) { - setOp1p(lhsp); - setOp2p(dtp); - dtypeFrom(dtp); - } - AstCast(FileLine* fl, AstNode* lhsp, AstNodeDType* dtp) - : ASTGEN_SUPER_Cast(fl) { - setOp1p(lhsp); - dtypeFrom(dtp); - } - ASTNODE_NODE_FUNCS(Cast) - virtual bool hasDType() const override { return true; } - virtual string emitVerilog() { return "((%d)'(%l))"; } - virtual bool cleanOut() const { V3ERROR_NA_RETURN(true); } - virtual bool cleanLhs() const { return true; } - virtual bool sizeMattersLhs() const { return false; } - AstNode* lhsp() const { return op1p(); } - AstNode* fromp() const { return lhsp(); } - void lhsp(AstNode* nodep) { setOp1p(nodep); } - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - AstNodeDType* childDTypep() const { return VN_AS(op2p(), NodeDType); } - virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } -}; - -class AstCastDynamic final : public AstNodeBiop { - // Verilog $cast used as a function - // Task usage of $cast is converted during parse to assert($cast(...)) - // Parents: MATH - // Children: MATH - // lhsp() is value (we are converting FROM) to match AstCCast etc, this - // is opposite of $cast's order, because the first access is to the - // value reading from. Suggest use fromp()/top() instead of lhsp/rhsp(). -public: - AstCastDynamic(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_CastDynamic(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(CastDynamic) - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - V3ERROR_NA; - } - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstCastDynamic(this->fileline(), lhsp, rhsp); - } - virtual string emitVerilog() override { return "%f$cast(%r, %l)"; } - virtual string emitC() override { return "VL_DYNAMIC_CAST(%r, %l)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 20; } - virtual bool isPure() const override { return true; } - AstNode* fromp() const { return lhsp(); } - AstNode* top() const { return rhsp(); } -}; - -class AstCastParse final : public AstNode { - // Cast to appropriate type, where we haven't determined yet what the data type is -public: - AstCastParse(FileLine* fl, AstNode* lhsp, AstNode* dtp) - : ASTGEN_SUPER_CastParse(fl) { - setOp1p(lhsp); - setOp2p(dtp); - } - ASTNODE_NODE_FUNCS(CastParse) - virtual string emitVerilog() { return "((%d)'(%l))"; } - virtual string emitC() { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const { V3ERROR_NA_RETURN(true); } - virtual bool cleanLhs() const { return true; } - virtual bool sizeMattersLhs() const { return false; } - AstNode* lhsp() const { return op1p(); } - AstNode* dtp() const { return op2p(); } -}; - -class AstCastSize final : public AstNode { - // Cast to specific size; signed/twostate inherited from lower element per IEEE -public: - AstCastSize(FileLine* fl, AstNode* lhsp, AstConst* rhsp) - : ASTGEN_SUPER_CastSize(fl) { - setOp1p(lhsp); - setOp2p(rhsp); - } - ASTNODE_NODE_FUNCS(CastSize) - // No hasDType because widthing removes this node before the hasDType check - virtual string emitVerilog() { return "((%r)'(%l))"; } - virtual bool cleanOut() const { V3ERROR_NA_RETURN(true); } - virtual bool cleanLhs() const { return true; } - virtual bool sizeMattersLhs() const { return false; } - AstNode* lhsp() const { return op1p(); } - AstNode* rhsp() const { return op2p(); } -}; - -class AstCCast final : public AstNodeUniop { - // Cast to C-based data type -private: - int m_size; - -public: - AstCCast(FileLine* fl, AstNode* lhsp, int setwidth, int minwidth = -1) - : ASTGEN_SUPER_CCast(fl, lhsp) { - m_size = setwidth; - if (setwidth) { - if (minwidth == -1) minwidth = setwidth; - dtypeSetLogicUnsized(setwidth, minwidth, VSigning::UNSIGNED); - } - } - AstCCast(FileLine* fl, AstNode* lhsp, AstNode* typeFromp) - : ASTGEN_SUPER_CCast(fl, lhsp) { - dtypeFrom(typeFromp); - m_size = width(); - } - ASTNODE_NODE_FUNCS(CCast) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAssign(lhs); } - virtual string emitVerilog() override { return "%f$_CAST(%l)"; } - virtual string emitC() override { return "VL_CAST_%nq%lq(%nw,%lw, %P, %li)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } // Special cased in V3Cast - virtual bool same(const AstNode* samep) const override { - return size() == static_cast(samep)->size(); - } - virtual void dump(std::ostream& str = std::cout) const override; - // - int size() const { return m_size; } -}; - -class AstCvtPackString final : public AstNodeUniop { - // Convert to Verilator Packed String (aka verilog "string") -public: - AstCvtPackString(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_CvtPackString(fl, lhsp) { - dtypeSetString(); - } - ASTNODE_NODE_FUNCS(CvtPackString) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } - virtual string emitVerilog() override { return "%f$_CAST(%l)"; } - virtual string emitC() override { return "VL_CVT_PACK_STR_N%lq(%lW, %li)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstFEof final : public AstNodeUniop { -public: - AstFEof(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_FEof(fl, lhsp) {} - ASTNODE_NODE_FUNCS(FEof) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } - virtual string emitVerilog() override { return "%f$feof(%l)"; } - virtual string emitC() override { return "(%li ? feof(VL_CVT_I_FP(%li)) : true)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 16; } - virtual bool isPure() const override { - return false; - } // SPECIAL: $display has 'visual' ordering - AstNode* filep() const { return lhsp(); } -}; - -class AstFError final : public AstNodeMath { -public: - AstFError(FileLine* fl, AstNode* filep, AstNode* strp) - : ASTGEN_SUPER_FError(fl) { - setOp1p(filep); - setOp2p(strp); - } - ASTNODE_NODE_FUNCS(FError) - virtual string emitVerilog() override { return "%f$ferror(%l, %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const { return true; } - virtual bool sizeMattersLhs() const { return false; } - virtual int instrCount() const override { return widthInstrs() * 64; } - virtual bool isPure() const override { - return false; - } // SPECIAL: $display has 'visual' ordering - void filep(AstNode* nodep) { setOp1p(nodep); } - AstNode* filep() const { return op1p(); } - void strp(AstNode* nodep) { setOp2p(nodep); } - AstNode* strp() const { return op2p(); } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstFGetC final : public AstNodeUniop { -public: - AstFGetC(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_FGetC(fl, lhsp) {} - ASTNODE_NODE_FUNCS(FGetC) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } - virtual string emitVerilog() override { return "%f$fgetc(%l)"; } - // Non-existent filehandle returns EOF - virtual string emitC() override { return "(%li ? fgetc(VL_CVT_I_FP(%li)) : -1)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 64; } - virtual bool isPure() const override { - return false; - } // SPECIAL: $display has 'visual' ordering - AstNode* filep() const { return lhsp(); } -}; - -class AstFUngetC final : public AstNodeBiop { -public: - AstFUngetC(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_FUngetC(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(FUngetC) - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - V3ERROR_NA; - } - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstFUngetC(this->fileline(), lhsp, rhsp); - } - virtual string emitVerilog() override { return "%f$ungetc(%r, %l)"; } - // Non-existent filehandle returns EOF - virtual string emitC() override { - return "(%li ? (ungetc(%ri, VL_CVT_I_FP(%li)) >= 0 ? 0 : -1) : -1)"; - } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 64; } - virtual bool isPure() const override { - return false; - } // SPECIAL: $display has 'visual' ordering - AstNode* filep() const { return lhsp(); } - AstNode* charp() const { return rhsp(); } -}; - -class AstNodeSystemUniop VL_NOT_FINAL : public AstNodeUniop { -public: - AstNodeSystemUniop(VNType t, FileLine* fl, AstNode* lhsp) - : AstNodeUniop(t, fl, lhsp) { - dtypeSetDouble(); - } - ASTNODE_BASE_FUNCS(NodeSystemUniop) - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL_TRIG; } - virtual bool doubleFlavor() const override { return true; } -}; - -class AstLogD final : public AstNodeSystemUniop { -public: - AstLogD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_LogD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(LogD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::log(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$ln(%l)"; } - virtual string emitC() override { return "log(%li)"; } -}; -class AstLog10D final : public AstNodeSystemUniop { -public: - AstLog10D(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_Log10D(fl, lhsp) {} - ASTNODE_NODE_FUNCS(Log10D) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::log10(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$log10(%l)"; } - virtual string emitC() override { return "log10(%li)"; } -}; - -class AstExpD final : public AstNodeSystemUniop { -public: - AstExpD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_ExpD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(ExpD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::exp(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$exp(%l)"; } - virtual string emitC() override { return "exp(%li)"; } -}; - -class AstSqrtD final : public AstNodeSystemUniop { -public: - AstSqrtD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_SqrtD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(SqrtD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::sqrt(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$sqrt(%l)"; } - virtual string emitC() override { return "sqrt(%li)"; } -}; - -class AstFloorD final : public AstNodeSystemUniop { -public: - AstFloorD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_FloorD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(FloorD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::floor(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$floor(%l)"; } - virtual string emitC() override { return "floor(%li)"; } -}; - -class AstCeilD final : public AstNodeSystemUniop { -public: - AstCeilD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_CeilD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(CeilD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::ceil(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$ceil(%l)"; } - virtual string emitC() override { return "ceil(%li)"; } -}; - -class AstSinD final : public AstNodeSystemUniop { -public: - AstSinD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_SinD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(SinD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::sin(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$sin(%l)"; } - virtual string emitC() override { return "sin(%li)"; } -}; - -class AstCosD final : public AstNodeSystemUniop { -public: - AstCosD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_CosD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(CosD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::cos(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$cos(%l)"; } - virtual string emitC() override { return "cos(%li)"; } -}; - -class AstTanD final : public AstNodeSystemUniop { -public: - AstTanD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_TanD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(TanD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::tan(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$tan(%l)"; } - virtual string emitC() override { return "tan(%li)"; } -}; - -class AstAsinD final : public AstNodeSystemUniop { -public: - AstAsinD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_AsinD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(AsinD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::asin(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$asin(%l)"; } - virtual string emitC() override { return "asin(%li)"; } -}; - -class AstAcosD final : public AstNodeSystemUniop { -public: - AstAcosD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_AcosD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(AcosD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::acos(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$acos(%l)"; } - virtual string emitC() override { return "acos(%li)"; } -}; - -class AstAtanD final : public AstNodeSystemUniop { -public: - AstAtanD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_AtanD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(AtanD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::atan(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$atan(%l)"; } - virtual string emitC() override { return "atan(%li)"; } -}; - -class AstSinhD final : public AstNodeSystemUniop { -public: - AstSinhD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_SinhD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(SinhD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::sinh(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$sinh(%l)"; } - virtual string emitC() override { return "sinh(%li)"; } -}; - -class AstCoshD final : public AstNodeSystemUniop { -public: - AstCoshD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_CoshD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(CoshD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::cosh(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$cosh(%l)"; } - virtual string emitC() override { return "cosh(%li)"; } -}; - -class AstTanhD final : public AstNodeSystemUniop { -public: - AstTanhD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_TanhD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(TanhD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::tanh(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$tanh(%l)"; } - virtual string emitC() override { return "tanh(%li)"; } -}; - -class AstAsinhD final : public AstNodeSystemUniop { -public: - AstAsinhD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_AsinhD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(AsinhD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::asinh(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$asinh(%l)"; } - virtual string emitC() override { return "asinh(%li)"; } -}; - -class AstAcoshD final : public AstNodeSystemUniop { -public: - AstAcoshD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_AcoshD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(AcoshD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::acosh(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$acosh(%l)"; } - virtual string emitC() override { return "acosh(%li)"; } -}; - -class AstAtanhD final : public AstNodeSystemUniop { -public: - AstAtanhD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_AtanhD(fl, lhsp) {} - ASTNODE_NODE_FUNCS(AtanhD) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.setDouble(std::atanh(lhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$atanh(%l)"; } - virtual string emitC() override { return "atanh(%li)"; } -}; -class AstToLowerN final : public AstNodeUniop { - // string.tolower() -public: - AstToLowerN(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_ToLowerN(fl, lhsp) { - dtypeSetString(); - } - ASTNODE_NODE_FUNCS(ToLowerN) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.opToLowerN(lhs); - } - virtual string emitVerilog() override { return "%l.tolower()"; } - virtual string emitC() override { return "VL_TOLOWER_NN(%li)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } -}; -class AstToUpperN final : public AstNodeUniop { - // string.toupper() -public: - AstToUpperN(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_ToUpperN(fl, lhsp) { - dtypeSetString(); - } - ASTNODE_NODE_FUNCS(ToUpperN) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.opToUpperN(lhs); - } - virtual string emitVerilog() override { return "%l.toupper()"; } - virtual string emitC() override { return "VL_TOUPPER_NN(%li)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } -}; -class AstTimeImport final : public AstNodeUniop { - // Take a constant that represents a time and needs conversion based on time units - VTimescale m_timeunit; // Parent module time unit -public: - AstTimeImport(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_TimeImport(fl, lhsp) {} - ASTNODE_NODE_FUNCS(TimeImport) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } - virtual string emitVerilog() override { return "%l"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual void dump(std::ostream& str = std::cout) const override; - void timeunit(const VTimescale& flag) { m_timeunit = flag; } - VTimescale timeunit() const { return m_timeunit; } -}; - -class AstAtoN final : public AstNodeUniop { - // string.atoi(), atobin(), atohex(), atooct(), atoireal() -public: - enum FmtType { ATOI = 10, ATOHEX = 16, ATOOCT = 8, ATOBIN = 2, ATOREAL = -1 }; - -private: - const FmtType m_fmt; // Operation type -public: - AstAtoN(FileLine* fl, AstNode* lhsp, FmtType fmt) - : ASTGEN_SUPER_AtoN(fl, lhsp) - , m_fmt{fmt} { - fmt == ATOREAL ? dtypeSetDouble() : dtypeSetSigned32(); - } - ASTNODE_NODE_FUNCS(AtoN) - virtual void numberOperate(V3Number& out, const V3Number& lhs) override { - out.opAtoN(lhs, m_fmt); - } - virtual string name() const override { - switch (m_fmt) { - case ATOI: return "atoi"; - case ATOHEX: return "atohex"; - case ATOOCT: return "atooct"; - case ATOBIN: return "atobin"; - case ATOREAL: return "atoreal"; - default: V3ERROR_NA; - } - } - virtual string emitVerilog() override { return "%l." + name() + "()"; } - virtual string emitC() override { - switch (m_fmt) { - case ATOI: return "VL_ATOI_N(%li, 10)"; - case ATOHEX: return "VL_ATOI_N(%li, 16)"; - case ATOOCT: return "VL_ATOI_N(%li, 8)"; - case ATOBIN: return "VL_ATOI_N(%li, 2)"; - case ATOREAL: return "std::atof(%li.c_str())"; - default: V3ERROR_NA; - } - } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - FmtType format() const { return m_fmt; } -}; - -//====================================================================== -// Binary ops - -class AstLogOr final : public AstNodeBiop { - // LOGOR with optional side effects - // Side effects currently used in some V3Width code - // TBD if this concept is generally adopted for side-effect tracking - // versus V3Const tracking it itself - bool m_sideEffect = false; // Has side effect, relies on short-circuiting -public: - AstLogOr(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_LogOr(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(LogOr) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLogOr(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLogOr(lhs, rhs); - } - virtual bool same(const AstNode* samep) const override { - const AstLogOr* const sp = static_cast(samep); - return m_sideEffect == sp->m_sideEffect; - } - virtual void dump(std::ostream& str = std::cout) const override; - virtual string emitVerilog() override { return "%k(%l %f|| %r)"; } - virtual string emitC() override { return "VL_LOGOR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "||"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } - virtual bool isPure() const override { return !m_sideEffect; } - void sideEffect(bool flag) { m_sideEffect = flag; } - bool sideEffect() const { return m_sideEffect; } -}; -class AstLogAnd final : public AstNodeBiop { -public: - AstLogAnd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_LogAnd(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(LogAnd) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLogAnd(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLogAnd(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f&& %r)"; } - virtual string emitC() override { return "VL_LOGAND_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "&&"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } -}; -class AstLogEq final : public AstNodeBiCom { -public: - AstLogEq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_LogEq(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(LogEq) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLogEq(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLogEq(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f<-> %r)"; } - virtual string emitC() override { return "VL_LOGEQ_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "<->"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } -}; -class AstLogIf final : public AstNodeBiop { -public: - AstLogIf(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_LogIf(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(LogIf) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLogIf(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLogIf(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f-> %r)"; } - virtual string emitC() override { return "VL_LOGIF_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "->"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; } -}; -class AstOr final : public AstNodeBiComAsv { -public: - AstOr(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Or(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(Or) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstOr(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opOr(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f| %r)"; } - virtual string emitC() override { return "VL_OR_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "|"; } - virtual bool cleanOut() const override { V3ERROR_NA_RETURN(false); } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstAnd final : public AstNodeBiComAsv { -public: - AstAnd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_And(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(And) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAnd(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opAnd(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f& %r)"; } - virtual string emitC() override { return "VL_AND_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "&"; } - virtual bool cleanOut() const override { V3ERROR_NA_RETURN(false); } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstXor final : public AstNodeBiComAsv { -public: - AstXor(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Xor(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(Xor) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstXor(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opXor(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f^ %r)"; } - virtual string emitC() override { return "VL_XOR_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "^"; } - virtual bool cleanOut() const override { return false; } // Lclean && Rclean - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstEq final : public AstNodeBiCom { -public: - AstEq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Eq(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(Eq) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstEq(this->fileline(), lhsp, rhsp); - } - static AstNodeBiop* newTyped(FileLine* fl, AstNode* lhsp, - AstNode* rhsp); // Return AstEq/AstEqD - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opEq(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f== %r)"; } - virtual string emitC() override { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "=="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstEqD final : public AstNodeBiCom { -public: - AstEqD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_EqD(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(EqD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstEqD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opEqD(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f== %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "=="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstEqN final : public AstNodeBiCom { -public: - AstEqN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_EqN(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(EqN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstEqN(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opEqN(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f== %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "=="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_STR; } - virtual bool stringFlavor() const override { return true; } -}; -class AstNeq final : public AstNodeBiCom { -public: - AstNeq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Neq(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(Neq) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstNeq(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opNeq(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f!= %r)"; } - virtual string emitC() override { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "!="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstNeqD final : public AstNodeBiCom { -public: - AstNeqD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_NeqD(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(NeqD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstNeqD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opNeqD(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f!= %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "!="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstNeqN final : public AstNodeBiCom { -public: - AstNeqN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_NeqN(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(NeqN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstNeqN(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opNeqN(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f!= %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "!="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_STR; } - virtual bool stringFlavor() const override { return true; } -}; -class AstLt final : public AstNodeBiop { -public: - AstLt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Lt(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(Lt) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLt(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLt(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f< %r)"; } - virtual string emitC() override { return "VL_LT_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "<"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstLtD final : public AstNodeBiop { -public: - AstLtD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_LtD(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(LtD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLtD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLtD(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f< %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "<"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstLtS final : public AstNodeBiop { -public: - AstLtS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_LtS(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(LtS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLtS(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLtS(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f< %r)"; } - virtual string emitC() override { return "VL_LTS_%nq%lq%rq(%lw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return ""; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool signedFlavor() const override { return true; } -}; -class AstLtN final : public AstNodeBiop { -public: - AstLtN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_LtN(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(LtN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLtN(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLtN(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f< %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "<"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_STR; } - virtual bool stringFlavor() const override { return true; } -}; -class AstGt final : public AstNodeBiop { -public: - AstGt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Gt(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(Gt) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstGt(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opGt(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f> %r)"; } - virtual string emitC() override { return "VL_GT_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return ">"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstGtD final : public AstNodeBiop { -public: - AstGtD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_GtD(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(GtD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstGtD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opGtD(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f> %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return ">"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstGtS final : public AstNodeBiop { -public: - AstGtS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_GtS(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(GtS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstGtS(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opGtS(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f> %r)"; } - virtual string emitC() override { return "VL_GTS_%nq%lq%rq(%lw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return ""; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool signedFlavor() const override { return true; } -}; -class AstGtN final : public AstNodeBiop { -public: - AstGtN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_GtN(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(GtN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstGtN(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opGtN(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f> %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return ">"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_STR; } - virtual bool stringFlavor() const override { return true; } -}; -class AstGte final : public AstNodeBiop { -public: - AstGte(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Gte(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(Gte) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstGte(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opGte(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f>= %r)"; } - virtual string emitC() override { return "VL_GTE_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return ">="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstGteD final : public AstNodeBiop { -public: - AstGteD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_GteD(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(GteD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstGteD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opGteD(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f>= %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return ">="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstGteS final : public AstNodeBiop { -public: - AstGteS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_GteS(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(GteS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstGteS(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opGteS(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f>= %r)"; } - virtual string emitC() override { return "VL_GTES_%nq%lq%rq(%lw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return ""; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool signedFlavor() const override { return true; } -}; -class AstGteN final : public AstNodeBiop { -public: - AstGteN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_GteN(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(GteN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstGteN(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opGteN(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f>= %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return ">="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_STR; } - virtual bool stringFlavor() const override { return true; } -}; -class AstLte final : public AstNodeBiop { -public: - AstLte(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Lte(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(Lte) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLte(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLte(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f<= %r)"; } - virtual string emitC() override { return "VL_LTE_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "<="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstLteD final : public AstNodeBiop { -public: - AstLteD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_LteD(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(LteD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLteD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLteD(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f<= %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "<="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstLteS final : public AstNodeBiop { -public: - AstLteS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_LteS(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(LteS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLteS(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLteS(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f<= %r)"; } - virtual string emitC() override { return "VL_LTES_%nq%lq%rq(%lw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return ""; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool signedFlavor() const override { return true; } -}; -class AstLteN final : public AstNodeBiop { -public: - AstLteN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_LteN(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(LteN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstLteN(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opLteN(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f<= %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "<="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_STR; } - virtual bool stringFlavor() const override { return true; } -}; -class AstShiftL final : public AstNodeBiop { -public: - AstShiftL(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) - : ASTGEN_SUPER_ShiftL(fl, lhsp, rhsp) { - if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); - } - ASTNODE_NODE_FUNCS(ShiftL) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstShiftL(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opShiftL(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f<< %r)"; } - virtual string emitC() override { return "VL_SHIFTL_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { - return (rhsp()->isWide() || rhsp()->isQuad()) ? "" : "<<"; - } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstShiftR final : public AstNodeBiop { -public: - AstShiftR(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) - : ASTGEN_SUPER_ShiftR(fl, lhsp, rhsp) { - if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); - } - ASTNODE_NODE_FUNCS(ShiftR) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstShiftR(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opShiftR(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f>> %r)"; } - virtual string emitC() override { return "VL_SHIFTR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { - return (rhsp()->isWide() || rhsp()->isQuad()) ? "" : ">>"; - } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - // LHS size might be > output size, so don't want to force size - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstShiftRS final : public AstNodeBiop { - // Shift right with sign extension, >>> operator - // Output data type's width determines which bit is used for sign extension -public: - AstShiftRS(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) - : ASTGEN_SUPER_ShiftRS(fl, lhsp, rhsp) { - // Important that widthMin be correct, as opExtend requires it after V3Expand - if (setwidth) dtypeSetLogicSized(setwidth, VSigning::SIGNED); - } - ASTNODE_NODE_FUNCS(ShiftRS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstShiftRS(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opShiftRS(lhs, rhs, lhsp()->widthMinV()); - } - virtual string emitVerilog() override { return "%k(%l %f>>> %r)"; } - virtual string emitC() override { return "VL_SHIFTRS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return ""; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool signedFlavor() const override { return true; } -}; -class AstAdd final : public AstNodeBiComAsv { -public: - AstAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Add(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(Add) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAdd(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opAdd(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f+ %r)"; } - virtual string emitC() override { return "VL_ADD_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "+"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } -}; -class AstAddD final : public AstNodeBiComAsv { -public: - AstAddD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_AddD(fl, lhsp, rhsp) { - dtypeSetDouble(); - } - ASTNODE_NODE_FUNCS(AddD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAddD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opAddD(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f+ %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "+"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstSub final : public AstNodeBiop { -public: - AstSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Sub(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(Sub) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstSub(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opSub(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f- %r)"; } - virtual string emitC() override { return "VL_SUB_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "-"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } -}; -class AstSubD final : public AstNodeBiop { -public: - AstSubD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_SubD(fl, lhsp, rhsp) { - dtypeSetDouble(); - } - ASTNODE_NODE_FUNCS(SubD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstSubD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opSubD(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f- %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "-"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstMul final : public AstNodeBiComAsv { -public: - AstMul(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Mul(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(Mul) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstMul(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opMul(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f* %r)"; } - virtual string emitC() override { return "VL_MUL_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "*"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } - virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL; } -}; -class AstMulD final : public AstNodeBiComAsv { -public: - AstMulD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_MulD(fl, lhsp, rhsp) { - dtypeSetDouble(); - } - ASTNODE_NODE_FUNCS(MulD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstMulD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opMulD(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f* %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "*"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } - virtual int instrCount() const override { return INSTR_COUNT_DBL; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstMulS final : public AstNodeBiComAsv { -public: - AstMulS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_MulS(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(MulS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstMulS(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opMulS(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f* %r)"; } - virtual string emitC() override { return "VL_MULS_%nq%lq%rq(%lw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return ""; } - virtual bool emitCheckMaxWords() override { return true; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } - virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL; } - virtual bool signedFlavor() const override { return true; } -}; -class AstDiv final : public AstNodeBiop { -public: - AstDiv(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Div(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(Div) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstDiv(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opDiv(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f/ %r)"; } - virtual string emitC() override { return "VL_DIV_%nq%lq%rq(%lw, %P, %li, %ri)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } - virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_DIV; } -}; -class AstDivD final : public AstNodeBiop { -public: - AstDivD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_DivD(fl, lhsp, rhsp) { - dtypeSetDouble(); - } - ASTNODE_NODE_FUNCS(DivD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstDivD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opDivD(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f/ %r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return "/"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL_DIV; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstDivS final : public AstNodeBiop { -public: - AstDivS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_DivS(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(DivS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstDivS(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opDivS(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f/ %r)"; } - virtual string emitC() override { return "VL_DIVS_%nq%lq%rq(%lw, %P, %li, %ri)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } - virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_DIV; } - virtual bool signedFlavor() const override { return true; } -}; -class AstModDiv final : public AstNodeBiop { -public: - AstModDiv(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_ModDiv(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(ModDiv) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstModDiv(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opModDiv(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f%% %r)"; } - virtual string emitC() override { return "VL_MODDIV_%nq%lq%rq(%lw, %P, %li, %ri)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } - virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_DIV; } -}; -class AstModDivS final : public AstNodeBiop { -public: - AstModDivS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_ModDivS(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(ModDivS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstModDivS(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opModDivS(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f%% %r)"; } - virtual string emitC() override { return "VL_MODDIVS_%nq%lq%rq(%lw, %P, %li, %ri)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } - virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_DIV; } - virtual bool signedFlavor() const override { return true; } -}; -class AstPow final : public AstNodeBiop { -public: - AstPow(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Pow(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(Pow) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstPow(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opPow(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f** %r)"; } - virtual string emitC() override { return "VL_POW_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } - virtual bool emitCheckMaxWords() override { return true; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL * 10; } -}; -class AstPowD final : public AstNodeBiop { -public: - AstPowD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_PowD(fl, lhsp, rhsp) { - dtypeSetDouble(); - } - ASTNODE_NODE_FUNCS(PowD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstPowD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opPowD(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f** %r)"; } - virtual string emitC() override { return "pow(%li,%ri)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL_DIV * 5; } - virtual bool doubleFlavor() const override { return true; } -}; -class AstPowSU final : public AstNodeBiop { -public: - AstPowSU(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_PowSU(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(PowSU) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstPowSU(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opPowSU(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f** %r)"; } - virtual string emitC() override { - return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 1,0)"; - } - virtual bool emitCheckMaxWords() override { return true; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL * 10; } - virtual bool signedFlavor() const override { return true; } -}; -class AstPowSS final : public AstNodeBiop { -public: - AstPowSS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_PowSS(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(PowSS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstPowSS(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opPowSS(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f** %r)"; } - virtual string emitC() override { - return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 1,1)"; - } - virtual bool emitCheckMaxWords() override { return true; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL * 10; } - virtual bool signedFlavor() const override { return true; } -}; -class AstPowUS final : public AstNodeBiop { -public: - AstPowUS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_PowUS(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(PowUS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstPowUS(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opPowUS(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f** %r)"; } - virtual string emitC() override { - return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 0,1)"; - } - virtual bool emitCheckMaxWords() override { return true; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * INSTR_COUNT_INT_MUL * 10; } - virtual bool signedFlavor() const override { return true; } -}; -class AstPreAdd final : public AstNodeTriop { - // Pre-increment/add - // Parents: MATH - // Children: lhsp: AstConst (1) as currently support only ++ not += - // Children: rhsp: tree with AstVarRef that is value to read before operation - // Children: thsp: tree with AstVarRef LValue that is stored after operation -public: - AstPreAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) - : ASTGEN_SUPER_PreAdd(fl, lhsp, rhsp, thsp) {} - ASTNODE_NODE_FUNCS(PreAdd) - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, - const V3Number& ths) override { - V3ERROR_NA; // Need to modify lhs - } - virtual string emitVerilog() override { return "%k(++%r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool cleanThs() const override { return false; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } - virtual bool sizeMattersThs() const override { return true; } -}; -class AstPreSub final : public AstNodeTriop { - // Pre-decrement/subtract - // Parents: MATH - // Children: lhsp: AstConst (1) as currently support only -- not -= - // Children: rhsp: tree with AstVarRef that is value to read before operation - // Children: thsp: tree with AstVarRef LValue that is stored after operation -public: - AstPreSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) - : ASTGEN_SUPER_PreSub(fl, lhsp, rhsp, thsp) {} - ASTNODE_NODE_FUNCS(PreSub) - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, - const V3Number& ths) override { - V3ERROR_NA; // Need to modify lhs - } - virtual string emitVerilog() override { return "%k(--%r)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool cleanThs() const override { return false; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } - virtual bool sizeMattersThs() const override { return true; } -}; -class AstPostAdd final : public AstNodeTriop { - // Post-increment/add - // Parents: MATH - // Children: lhsp: AstConst (1) as currently support only ++ not += - // Children: rhsp: tree with AstVarRef that is value to read before operation - // Children: thsp: tree with AstVarRef LValue that is stored after operation -public: - AstPostAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) - : ASTGEN_SUPER_PostAdd(fl, lhsp, rhsp, thsp) {} - ASTNODE_NODE_FUNCS(PostAdd) - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, - const V3Number& ths) override { - V3ERROR_NA; // Need to modify lhs - } - virtual string emitVerilog() override { return "%k(%r++)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool cleanThs() const override { return false; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } - virtual bool sizeMattersThs() const override { return true; } -}; -class AstPostSub final : public AstNodeTriop { - // Post-decrement/subtract - // Parents: MATH - // Children: lhsp: AstConst (1) as currently support only -- not -= - // Children: rhsp: tree with AstVarRef that is value to read before operation - // Children: thsp: tree with AstVarRef LValue that is stored after operation -public: - AstPostSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) - : ASTGEN_SUPER_PostSub(fl, lhsp, rhsp, thsp) {} - ASTNODE_NODE_FUNCS(PostSub) - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, - const V3Number& ths) override { - V3ERROR_NA; // Need to modify lhs - } - virtual string emitVerilog() override { return "%k(%r--)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool cleanThs() const override { return false; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return true; } - virtual bool sizeMattersThs() const override { return true; } -}; -class AstEqCase final : public AstNodeBiCom { -public: - AstEqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_EqCase(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(EqCase) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstEqCase(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opCaseEq(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f=== %r)"; } - virtual string emitC() override { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "=="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstNeqCase final : public AstNodeBiCom { -public: - AstNeqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_NeqCase(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(NeqCase) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstNeqCase(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opCaseNeq(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f!== %r)"; } - virtual string emitC() override { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "!="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstEqWild final : public AstNodeBiop { - // Note wildcard operator rhs differs from lhs -public: - AstEqWild(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_EqWild(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(EqWild) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstEqWild(this->fileline(), lhsp, rhsp); - } - static AstNodeBiop* newTyped(FileLine* fl, AstNode* lhsp, - AstNode* rhsp); // Return AstEqWild/AstEqD - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opWildEq(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f==? %r)"; } - virtual string emitC() override { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "=="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstNeqWild final : public AstNodeBiop { -public: - AstNeqWild(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_NeqWild(fl, lhsp, rhsp) { - dtypeSetBit(); - } - ASTNODE_NODE_FUNCS(NeqWild) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstNeqWild(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opWildNeq(lhs, rhs); - } - virtual string emitVerilog() override { return "%k(%l %f!=? %r)"; } - virtual string emitC() override { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "!="; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstConcat final : public AstNodeBiop { - // If you're looking for {#{}}, see AstReplicate -public: - AstConcat(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Concat(fl, lhsp, rhsp) { - if (lhsp->dtypep() && rhsp->dtypep()) { - dtypeSetLogicSized(lhsp->dtypep()->width() + rhsp->dtypep()->width(), - VSigning::UNSIGNED); - } - } - ASTNODE_NODE_FUNCS(Concat) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstConcat(this->fileline(), lhsp, rhsp); - } - virtual string emitVerilog() override { return "%f{%l, %k%r}"; } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opConcat(lhs, rhs); - } - virtual string emitC() override { return "VL_CONCAT_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 2; } -}; -class AstConcatN final : public AstNodeBiop { - // String concatenate -public: - AstConcatN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_ConcatN(fl, lhsp, rhsp) { - dtypeSetString(); - } - ASTNODE_NODE_FUNCS(ConcatN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstConcatN(this->fileline(), lhsp, rhsp); - } - virtual string emitVerilog() override { return "%f{%l, %k%r}"; } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opConcatN(lhs, rhs); - } - virtual string emitC() override { return "VL_CONCATN_NNN(%li, %ri)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_STR; } - virtual bool stringFlavor() const override { return true; } -}; -class AstReplicate final : public AstNodeBiop { - // Also used as a "Uniop" flavor of Concat, e.g. "{a}" - // Verilog {rhs{lhs}} - Note rhsp() is the replicate value, not the lhsp() -public: - AstReplicate(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Replicate(fl, lhsp, rhsp) { - if (lhsp) { - if (const AstConst* const constp = VN_CAST(rhsp, Const)) { - dtypeSetLogicSized(lhsp->width() * constp->toUInt(), VSigning::UNSIGNED); - } - } - } - AstReplicate(FileLine* fl, AstNode* lhsp, uint32_t repCount) - : AstReplicate(fl, lhsp, new AstConst(fl, repCount)) {} - ASTNODE_NODE_FUNCS(Replicate) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstReplicate(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opRepl(lhs, rhs); - } - virtual string emitVerilog() override { return "%f{%r{%k%l}}"; } - virtual string emitC() override { return "VL_REPLICATE_%nq%lq%rq(%lw, %P, %li, %ri)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 2; } -}; -class AstReplicateN final : public AstNodeBiop { - // String replicate -public: - AstReplicateN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_ReplicateN(fl, lhsp, rhsp) { - dtypeSetString(); - } - AstReplicateN(FileLine* fl, AstNode* lhsp, uint32_t repCount) - : AstReplicateN(fl, lhsp, new AstConst(fl, repCount)) {} - ASTNODE_NODE_FUNCS(ReplicateN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstReplicateN(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opReplN(lhs, rhs); - } - virtual string emitVerilog() override { return "%f{%r{%k%l}}"; } - virtual string emitC() override { return "VL_REPLICATEN_NN%rq(%li, %ri)"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 2; } - virtual bool stringFlavor() const override { return true; } -}; -class AstStreamL final : public AstNodeStream { - // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() -public: - AstStreamL(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_StreamL(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(StreamL) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstStreamL(this->fileline(), lhsp, rhsp); - } - virtual string emitVerilog() override { return "%f{ << %r %k{%l} }"; } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opStreamL(lhs, rhs); - } - virtual string emitC() override { return "VL_STREAML_%nq%lq%rq(%lw, %P, %li, %ri)"; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 2; } -}; -class AstStreamR final : public AstNodeStream { - // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() -public: - AstStreamR(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_StreamR(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(StreamR) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstStreamR(this->fileline(), lhsp, rhsp); - } - virtual string emitVerilog() override { return "%f{ >> %r %k{%l} }"; } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opAssign(lhs); - } - virtual string emitC() override { return isWide() ? "VL_ASSIGN_W(%nw, %P, %li)" : "%li"; } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return true; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 2; } -}; -class AstBufIf1 final : public AstNodeBiop { - // lhs is enable, rhs is data to drive - // Note unlike the Verilog bufif1() UDP, this allows any width; each lhsp - // bit enables respective rhsp bit -public: - AstBufIf1(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_BufIf1(fl, lhsp, rhsp) { - dtypeFrom(lhsp); - } - ASTNODE_NODE_FUNCS(BufIf1) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstBufIf1(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opBufIf1(lhs, rhs); - } - virtual string emitVerilog() override { return "bufif(%r,%l)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } // Lclean || Rclean - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } // Lclean || Rclean - virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } // Lclean || Rclean - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; -class AstFGetS final : public AstNodeBiop { -public: - AstFGetS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_FGetS(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(FGetS) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstFGetS(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - V3ERROR_NA; - } - virtual string emitVerilog() override { return "%f$fgets(%l,%r)"; } - virtual string emitC() override { - return strgp()->dtypep()->basicp()->isString() ? "VL_FGETS_NI(%li, %ri)" - : "VL_FGETS_%nqX%rq(%lw, %P, &(%li), %ri)"; - } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return widthInstrs() * 64; } - AstNode* strgp() const { return lhsp(); } - AstNode* filep() const { return rhsp(); } -}; - -class AstNodeSystemBiop VL_NOT_FINAL : public AstNodeBiop { -public: - AstNodeSystemBiop(VNType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : AstNodeBiop(t, fl, lhsp, rhsp) { - dtypeSetDouble(); - } - virtual bool cleanOut() const override { return false; } - virtual bool cleanLhs() const override { return false; } - virtual bool cleanRhs() const override { return false; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual int instrCount() const override { return INSTR_COUNT_DBL_TRIG; } - virtual bool doubleFlavor() const override { return true; } -}; - -class AstAtan2D final : public AstNodeSystemBiop { -public: - AstAtan2D(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_Atan2D(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(Atan2D) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAtan2D(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.setDouble(std::atan2(lhs.toDouble(), rhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$atan2(%l,%r)"; } - virtual string emitC() override { return "atan2(%li,%ri)"; } -}; - -class AstHypotD final : public AstNodeSystemBiop { -public: - AstHypotD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_HypotD(fl, lhsp, rhsp) {} - ASTNODE_NODE_FUNCS(HypotD) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstHypotD(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.setDouble(std::hypot(lhs.toDouble(), rhs.toDouble())); - } - virtual string emitVerilog() override { return "%f$hypot(%l,%r)"; } - virtual string emitC() override { return "hypot(%li,%ri)"; } -}; - -class AstPutcN final : public AstNodeTriop { - // Verilog string.putc() -public: - AstPutcN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* ths) - : ASTGEN_SUPER_PutcN(fl, lhsp, rhsp, ths) { - dtypeSetString(); - } - ASTNODE_NODE_FUNCS(PutcN) - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, - const V3Number& ths) override { - out.opPutcN(lhs, rhs, ths); - } - virtual string name() const override { return "putc"; } - virtual string emitVerilog() override { return "%k(%l.putc(%r,%t))"; } - virtual string emitC() override { return "VL_PUTC_N(%li,%ri,%ti)"; } - virtual string emitSimpleOperator() override { return ""; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool cleanThs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool sizeMattersThs() const override { return false; } -}; - -class AstGetcN final : public AstNodeBiop { - // Verilog string.getc() -public: - AstGetcN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_GetcN(fl, lhsp, rhsp) { - dtypeSetBitSized(8, VSigning::UNSIGNED); - } - ASTNODE_NODE_FUNCS(GetcN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstGetcN(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opGetcN(lhs, rhs); - } - virtual string name() const override { return "getc"; } - virtual string emitVerilog() override { return "%k(%l.getc(%r))"; } - virtual string emitC() override { return "VL_GETC_N(%li,%ri)"; } - virtual string emitSimpleOperator() override { return ""; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; - -class AstGetcRefN final : public AstNodeBiop { - // Verilog string[#] on the left-hand-side of assignment - // Spec says is of type byte (not string of single character) -public: - AstGetcRefN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_GetcRefN(fl, lhsp, rhsp) { - dtypeSetBitSized(8, VSigning::UNSIGNED); - } - ASTNODE_NODE_FUNCS(GetcRefN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstGetcRefN(this->fileline(), lhsp, rhsp); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - V3ERROR_NA; - } - virtual string emitVerilog() override { return "%k%l[%r]"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { return ""; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; - -class AstSubstrN final : public AstNodeTriop { - // Verilog string.substr() -public: - AstSubstrN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* ths) - : ASTGEN_SUPER_SubstrN(fl, lhsp, rhsp, ths) { - dtypeSetString(); - } - ASTNODE_NODE_FUNCS(SubstrN) - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, - const V3Number& ths) override { - out.opSubstrN(lhs, rhs, ths); - } - virtual string name() const override { return "substr"; } - virtual string emitVerilog() override { return "%k(%l.substr(%r,%t))"; } - virtual string emitC() override { return "VL_SUBSTR_N(%li,%ri,%ti)"; } - virtual string emitSimpleOperator() override { return ""; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool cleanThs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } - virtual bool sizeMattersThs() const override { return false; } -}; - -class AstCompareNN final : public AstNodeBiop { - // Verilog str.compare() and str.icompare() -private: - const bool m_ignoreCase; // True for str.icompare() -public: - AstCompareNN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, bool ignoreCase) - : ASTGEN_SUPER_CompareNN(fl, lhsp, rhsp) - , m_ignoreCase{ignoreCase} { - dtypeSetUInt32(); - } - ASTNODE_NODE_FUNCS(CompareNN) - virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstCompareNN(this->fileline(), lhsp, rhsp, m_ignoreCase); - } - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { - out.opCompareNN(lhs, rhs, m_ignoreCase); - } - virtual string name() const override { return m_ignoreCase ? "icompare" : "compare"; } - virtual string emitVerilog() override { - return m_ignoreCase ? "%k(%l.icompare(%r))" : "%k(%l.compare(%r))"; - } - virtual string emitC() override { - return m_ignoreCase ? "VL_CMP_NN(%li,%ri,true)" : "VL_CMP_NN(%li,%ri,false)"; - } - virtual string emitSimpleOperator() override { return ""; } - virtual bool cleanOut() const override { return true; } - virtual bool cleanLhs() const override { return true; } - virtual bool cleanRhs() const override { return true; } - virtual bool sizeMattersLhs() const override { return false; } - virtual bool sizeMattersRhs() const override { return false; } -}; - -class AstFell final : public AstNodeMath { - // Verilog $fell - // Parents: math - // Children: expression -public: - AstFell(FileLine* fl, AstNode* exprp) - : ASTGEN_SUPER_Fell(fl) { - addOp1p(exprp); - } - ASTNODE_NODE_FUNCS(Fell) - virtual string emitVerilog() override { return "$fell(%l)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* exprp() const { return op1p(); } // op1 = expression - AstSenTree* sentreep() const { return VN_AS(op2p(), SenTree); } // op2 = clock domain - void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstPast final : public AstNodeMath { - // Verilog $past - // Parents: math - // Children: expression -public: - AstPast(FileLine* fl, AstNode* exprp, AstNode* ticksp) - : ASTGEN_SUPER_Past(fl) { - addOp1p(exprp); - addNOp2p(ticksp); - } - ASTNODE_NODE_FUNCS(Past) - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* exprp() const { return op1p(); } // op1 = expression - AstNode* ticksp() const { return op2p(); } // op2 = ticks or nullptr means 1 - AstSenTree* sentreep() const { return VN_AS(op4p(), SenTree); } // op4 = clock domain - void sentreep(AstSenTree* sentreep) { addOp4p(sentreep); } // op4 = clock domain - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstRose final : public AstNodeMath { - // Verilog $rose - // Parents: math - // Children: expression -public: - AstRose(FileLine* fl, AstNode* exprp) - : ASTGEN_SUPER_Rose(fl) { - addOp1p(exprp); - } - ASTNODE_NODE_FUNCS(Rose) - virtual string emitVerilog() override { return "$rose(%l)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* exprp() const { return op1p(); } // op1 = expression - AstSenTree* sentreep() const { return VN_AS(op2p(), SenTree); } // op2 = clock domain - void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstSampled final : public AstNodeMath { - // Verilog $sampled - // Parents: math - // Children: expression -public: - AstSampled(FileLine* fl, AstNode* exprp) - : ASTGEN_SUPER_Sampled(fl) { - addOp1p(exprp); - } - ASTNODE_NODE_FUNCS(Sampled) - virtual string emitVerilog() override { return "$sampled(%l)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } - virtual int instrCount() const override { return 0; } - AstNode* exprp() const { return op1p(); } // op1 = expression - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstStable final : public AstNodeMath { - // Verilog $stable - // Parents: math - // Children: expression -public: - AstStable(FileLine* fl, AstNode* exprp) - : ASTGEN_SUPER_Stable(fl) { - addOp1p(exprp); - } - ASTNODE_NODE_FUNCS(Stable) - virtual string emitVerilog() override { return "$stable(%l)"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* exprp() const { return op1p(); } // op1 = expression - AstSenTree* sentreep() const { return VN_AS(op2p(), SenTree); } // op2 = clock domain - void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -class AstPattern final : public AstNodeMath { - // Verilog '{a,b,c,d...} - // Parents: AstNodeAssign, AstPattern, ... - // Children: expression, AstPattern, AstPatReplicate -public: - AstPattern(FileLine* fl, AstNode* itemsp) - : ASTGEN_SUPER_Pattern(fl) { - addNOp2p(itemsp); - } - ASTNODE_NODE_FUNCS(Pattern) - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } - virtual int instrCount() const override { return widthInstrs(); } - virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } - virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } - // op1 = Type assigning to - AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); } - void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } - AstNode* itemsp() const { return op2p(); } // op2 = AstPatReplicate, AstPatMember, etc - void addItemsp(AstNode* nodep) { addOp2p(nodep); } -}; -class AstPatMember final : public AstNodeMath { - // Verilog '{a} or '{a{b}} - // Parents: AstPattern - // Children: expression, AstPattern, replication count -private: - bool m_default = false; - -public: - AstPatMember(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* repp) - : ASTGEN_SUPER_PatMember(fl) { - addOp1p(lhsp), setNOp2p(keyp), setNOp3p(repp); - } - ASTNODE_NODE_FUNCS(PatMember) - virtual string emitVerilog() override { return lhssp() ? "%f{%r{%k%l}}" : "%l"; } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } - virtual int instrCount() const override { return widthInstrs() * 2; } - virtual void dump(std::ostream& str = std::cout) const override; - // op1 = expression to assign or another AstPattern (list if replicated) - AstNode* lhssp() const { return op1p(); } - AstNode* keyp() const { return op2p(); } // op2 = assignment key (Const, id Text) - AstNode* repp() const { return op3p(); } // op3 = replication count, or nullptr for count 1 - bool isDefault() const { return m_default; } - void isDefault(bool flag) { m_default = flag; } -}; - -class AstImplication final : public AstNodeMath { - // Verilog |-> |=> - // Parents: math - // Children: expression -public: - AstImplication(FileLine* fl, AstNode* lhs, AstNode* rhs) - : ASTGEN_SUPER_Implication(fl) { - setOp1p(lhs); - setOp2p(rhs); - } - ASTNODE_NODE_FUNCS(Implication) - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } - virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } - virtual int instrCount() const override { return widthInstrs(); } - AstNode* lhsp() const { return op1p(); } - AstNode* rhsp() const { return op2p(); } - void lhsp(AstNode* nodep) { return setOp1p(nodep); } - void rhsp(AstNode* nodep) { return setOp2p(nodep); } - AstSenTree* sentreep() const { return VN_AS(op4p(), SenTree); } // op4 = clock domain - void sentreep(AstSenTree* sentreep) { addOp4p(sentreep); } // op4 = clock domain - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -//====================================================================== -// Assertions - -class AstClocking final : public AstNode { - // Set default clock region - // Parents: MODULE - // Children: Assertions -public: - AstClocking(FileLine* fl, AstSenItem* sensesp, AstNode* bodysp) - : ASTGEN_SUPER_Clocking(fl) { - addOp1p(sensesp); - addNOp2p(bodysp); - } - ASTNODE_NODE_FUNCS(Clocking) - // op1 = Sensitivity list - AstSenItem* sensesp() const { return VN_AS(op1p(), SenItem); } - AstNode* bodysp() const { return op2p(); } // op2 = Body -}; - -//====================================================================== -// PSL - -class AstPropClocked final : public AstNode { - // A clocked property - // Parents: ASSERT|COVER (property) - // Children: SENITEM, Properties -public: - AstPropClocked(FileLine* fl, AstSenItem* sensesp, AstNode* disablep, AstNode* propp) - : ASTGEN_SUPER_PropClocked(fl) { - addNOp1p(sensesp); - addNOp2p(disablep); - addOp3p(propp); - } - ASTNODE_NODE_FUNCS(PropClocked) - virtual bool hasDType() const override { - return true; - } // Used under Cover, which expects a bool child - AstSenItem* sensesp() const { return VN_AS(op1p(), SenItem); } // op1 = Sensitivity list - AstNode* disablep() const { return op2p(); } // op2 = disable - AstNode* propp() const { return op3p(); } // op3 = property -}; - -class AstNodeCoverOrAssert VL_NOT_FINAL : public AstNodeStmt { - // Cover or Assert - // Parents: {statement list} - // Children: expression, report string -private: - const bool m_immediate; // Immediate assertion/cover - string m_name; // Name to report -public: - AstNodeCoverOrAssert(VNType t, FileLine* fl, AstNode* propp, AstNode* passsp, bool immediate, - const string& name = "") - : AstNodeStmt{t, fl} - , m_immediate{immediate} - , m_name{name} { - addOp1p(propp); - addNOp4p(passsp); - } - ASTNODE_BASE_FUNCS(NodeCoverOrAssert) - virtual string name() const override { return m_name; } // * = Var name - virtual bool same(const AstNode* samep) const override { return samep->name() == name(); } - virtual void name(const string& name) override { m_name = name; } - virtual void dump(std::ostream& str = std::cout) const override; - AstNode* propp() const { return op1p(); } // op1 = property - AstSenTree* sentreep() const { return VN_AS(op2p(), SenTree); } // op2 = clock domain - void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain - AstNode* passsp() const { return op4p(); } // op4 = statements (assert/cover passes) - bool immediate() const { return m_immediate; } -}; - -class AstAssert final : public AstNodeCoverOrAssert { -public: - ASTNODE_NODE_FUNCS(Assert) - AstAssert(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp, bool immediate, - const string& name = "") - : ASTGEN_SUPER_Assert(fl, propp, passsp, immediate, name) { - addNOp3p(failsp); - } - AstNode* failsp() const { return op3p(); } // op3 = if assertion fails -}; - -class AstAssertIntrinsic final : public AstNodeCoverOrAssert { - // A $cast or other compiler inserted assert, that must run even without --assert option -public: - ASTNODE_NODE_FUNCS(AssertIntrinsic) - AstAssertIntrinsic(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp, - bool immediate, const string& name = "") - : ASTGEN_SUPER_AssertIntrinsic(fl, propp, passsp, immediate, name) { - addNOp3p(failsp); - } - AstNode* failsp() const { return op3p(); } // op3 = if assertion fails -}; - -class AstCover final : public AstNodeCoverOrAssert { -public: - ASTNODE_NODE_FUNCS(Cover) - AstCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, bool immediate, - const string& name = "") - : ASTGEN_SUPER_Cover(fl, propp, stmtsp, immediate, name) {} - AstNode* coverincp() const { return op3p(); } // op3 = coverage node - void coverincp(AstCoverInc* nodep) { addOp3p(nodep); } // op3 = coverage node - virtual bool immediate() const { return false; } -}; - -class AstRestrict final : public AstNodeCoverOrAssert { -public: - ASTNODE_NODE_FUNCS(Restrict) - AstRestrict(FileLine* fl, AstNode* propp) - : ASTGEN_SUPER_Restrict(fl, propp, nullptr, false, "") {} -}; - -//====================================================================== -// Text based nodes - -class AstNodeSimpleText VL_NOT_FINAL : public AstNodeText { -private: - bool m_tracking; // When emit, it's ok to parse the string to do indentation -public: - AstNodeSimpleText(VNType t, FileLine* fl, const string& textp, bool tracking = false) - : AstNodeText(t, fl, textp) - , m_tracking(tracking) {} - ASTNODE_BASE_FUNCS(NodeSimpleText) - void tracking(bool flag) { m_tracking = flag; } - bool tracking() const { return m_tracking; } -}; - -class AstText final : public AstNodeSimpleText { -public: - AstText(FileLine* fl, const string& textp, bool tracking = false) - : ASTGEN_SUPER_Text(fl, textp, tracking) {} - ASTNODE_NODE_FUNCS(Text) -}; - -class AstTextBlock final : public AstNodeSimpleText { -private: - bool m_commas; // Comma separate emitted children -public: - explicit AstTextBlock(FileLine* fl, const string& textp = "", bool tracking = false, - bool commas = false) - : ASTGEN_SUPER_TextBlock(fl, textp, tracking) - , m_commas(commas) {} - ASTNODE_NODE_FUNCS(TextBlock) - void commas(bool flag) { m_commas = flag; } - bool commas() const { return m_commas; } - AstNode* nodesp() const { return op1p(); } - void addNodep(AstNode* nodep) { addOp1p(nodep); } - void addText(FileLine* fl, const string& textp, bool tracking = false) { - addNodep(new AstText(fl, textp, tracking)); - } -}; - -class AstScCtor final : public AstNodeText { -public: - AstScCtor(FileLine* fl, const string& textp) - : ASTGEN_SUPER_ScCtor(fl, textp) {} - ASTNODE_NODE_FUNCS(ScCtor) - virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs - virtual bool isOutputter() const override { return true; } -}; - -class AstScDtor final : public AstNodeText { -public: - AstScDtor(FileLine* fl, const string& textp) - : ASTGEN_SUPER_ScDtor(fl, textp) {} - ASTNODE_NODE_FUNCS(ScDtor) - virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs - virtual bool isOutputter() const override { return true; } -}; - -class AstScHdr final : public AstNodeText { -public: - AstScHdr(FileLine* fl, const string& textp) - : ASTGEN_SUPER_ScHdr(fl, textp) {} - ASTNODE_NODE_FUNCS(ScHdr) - virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs - virtual bool isOutputter() const override { return true; } -}; - -class AstScImp final : public AstNodeText { -public: - AstScImp(FileLine* fl, const string& textp) - : ASTGEN_SUPER_ScImp(fl, textp) {} - ASTNODE_NODE_FUNCS(ScImp) - virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs - virtual bool isOutputter() const override { return true; } -}; - -class AstScImpHdr final : public AstNodeText { -public: - AstScImpHdr(FileLine* fl, const string& textp) - : ASTGEN_SUPER_ScImpHdr(fl, textp) {} - ASTNODE_NODE_FUNCS(ScImpHdr) - virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs - virtual bool isOutputter() const override { return true; } -}; - -class AstScInt final : public AstNodeText { -public: - AstScInt(FileLine* fl, const string& textp) - : ASTGEN_SUPER_ScInt(fl, textp) {} - ASTNODE_NODE_FUNCS(ScInt) - virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs - virtual bool isOutputter() const override { return true; } -}; - -class AstUCStmt final : public AstNodeStmt { - // User $c statement -public: - AstUCStmt(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER_UCStmt(fl) { - addNOp1p(exprsp); - } - ASTNODE_NODE_FUNCS(UCStmt) - AstNode* bodysp() const { return op1p(); } // op1 = expressions to print - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return true; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } -}; - -//====================================================================== -// Emitted file nodes - -class AstNodeFile VL_NOT_FINAL : public AstNode { - // Emitted Otput file - // Parents: NETLIST - // Children: AstTextBlock -private: - string m_name; ///< Filename -public: - AstNodeFile(VNType t, FileLine* fl, const string& name) - : AstNode(t, fl) { - m_name = name; - } - ASTNODE_BASE_FUNCS(NodeFile) - virtual void dump(std::ostream& str) const override; - virtual string name() const override { return m_name; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - void tblockp(AstTextBlock* tblockp) { setOp1p(tblockp); } - AstTextBlock* tblockp() { return VN_AS(op1p(), TextBlock); } -}; - -//====================================================================== -// Emit V nodes - -class AstVFile final : public AstNodeFile { - // Verilog output file - // Parents: NETLIST -public: - AstVFile(FileLine* fl, const string& name) - : ASTGEN_SUPER_VFile(fl, name) {} - ASTNODE_NODE_FUNCS(VFile) - virtual void dump(std::ostream& str = std::cout) const override; -}; - -//====================================================================== -// Emit C nodes - -class AstCFile final : public AstNodeFile { - // C++ output file - // Parents: NETLIST -private: - bool m_slow : 1; ///< Compile w/o optimization - bool m_source : 1; ///< Source file (vs header file) - bool m_support : 1; ///< Support file (non systemc) -public: - AstCFile(FileLine* fl, const string& name) - : ASTGEN_SUPER_CFile(fl, name) - , m_slow{false} - , m_source{false} - , m_support{false} {} - ASTNODE_NODE_FUNCS(CFile) - virtual void dump(std::ostream& str = std::cout) const override; - bool slow() const { return m_slow; } - void slow(bool flag) { m_slow = flag; } - bool source() const { return m_source; } - void source(bool flag) { m_source = flag; } - bool support() const { return m_support; } - void support(bool flag) { m_support = flag; } -}; - -class AstCFunc final : public AstNode { - // C++ function - // Parents: MODULE/SCOPE - // Children: VAR/statements -private: - AstScope* m_scopep; - string m_name; - string m_cname; // C name, for dpiExports - string m_rtnType; // void, bool, or other return type - string m_argTypes; // Argument types - string m_ctorInits; // Constructor sub-class inits - string m_ifdef; // #ifdef symbol around this function - VBoolOrUnknown m_isConst; // Function is declared const (*this not changed) - bool m_isStatic : 1; // Function is static (no need for a 'this' pointer) - bool m_isTrace : 1; // Function is related to tracing - bool m_dontCombine : 1; // V3Combine shouldn't compare this func tree, it's special - bool m_declPrivate : 1; // Declare it private - bool m_isFinal : 1; // This is a function corresponding to a SystemVerilog 'final' block - bool m_slow : 1; // Slow routine, called once or just at init time - bool m_funcPublic : 1; // From user public task/function - bool m_isConstructor : 1; // Is C class constructor - bool m_isDestructor : 1; // Is C class destructor - bool m_isMethod : 1; // Is inside a class definition - bool m_isLoose : 1; // Semantically this is a method, but is implemented as a function - // with an explicitly passed 'self' pointer as the first argument - bool m_isInline : 1; // Inline function - bool m_isVirtual : 1; // Virtual function - bool m_entryPoint : 1; // User may call into this top level function - bool m_pure : 1; // Pure function - bool m_dpiContext : 1; // Declared as 'context' DPI import/export function - bool m_dpiExportDispatcher : 1; // This is the DPI export entry point (i.e.: called by user) - bool m_dpiExportImpl : 1; // DPI export implementation (called from DPI dispatcher via lookup) - bool m_dpiImportPrototype : 1; // This is the DPI import prototype (i.e.: provided by user) - bool m_dpiImportWrapper : 1; // Wrapper for invoking DPI import prototype from generated code - bool m_dpiTraceInit : 1; // DPI trace_init -public: - AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType = "") - : ASTGEN_SUPER_CFunc(fl) { - m_isConst = VBoolOrUnknown::BU_UNKNOWN; // Unknown until analyzed - m_scopep = scopep; - m_name = name; - m_rtnType = rtnType; - m_isStatic = false; - m_isTrace = false; - m_dontCombine = false; - m_declPrivate = false; - m_isFinal = false; - m_slow = false; - m_funcPublic = false; - m_isConstructor = false; - m_isDestructor = false; - m_isMethod = true; - m_isLoose = false; - m_isInline = false; - m_isVirtual = false; - m_entryPoint = false; - m_pure = false; - m_dpiContext = false; - m_dpiExportDispatcher = false; - m_dpiExportImpl = false; - m_dpiImportPrototype = false; - m_dpiImportWrapper = false; - m_dpiTraceInit = false; - } - ASTNODE_NODE_FUNCS(CFunc) - virtual string name() const override { return m_name; } - virtual const char* broken() const override { - BROKEN_RTN((m_scopep && !m_scopep->brokeExists())); - return nullptr; - } - virtual void cloneRelink() override { - if (m_scopep && m_scopep->clonep()) m_scopep = m_scopep->clonep(); - } - virtual bool maybePointedTo() const override { return true; } - virtual void dump(std::ostream& str = std::cout) const override; - virtual bool same(const AstNode* samep) const override { - const AstCFunc* const asamep = static_cast(samep); - return ((isTrace() == asamep->isTrace()) && (rtnTypeVoid() == asamep->rtnTypeVoid()) - && (argTypes() == asamep->argTypes()) && (ctorInits() == asamep->ctorInits()) - && isLoose() == asamep->isLoose() - && (!(dpiImportPrototype() || dpiExportImpl()) || name() == asamep->name())); - } - // - virtual void name(const string& name) override { m_name = name; } - virtual int instrCount() const override { - return dpiImportPrototype() ? v3Global.opt.instrCountDpi() : 0; - } - VBoolOrUnknown isConst() const { return m_isConst; } - void isConst(bool flag) { m_isConst.setTrueOrFalse(flag); } - void isConst(VBoolOrUnknown flag) { m_isConst = flag; } - bool isStatic() const { return m_isStatic; } - void isStatic(bool flag) { m_isStatic = flag; } - bool isTrace() const { return m_isTrace; } - void isTrace(bool flag) { m_isTrace = flag; } - void cname(const string& name) { m_cname = name; } - string cname() const { return m_cname; } - AstScope* scopep() const { return m_scopep; } - void scopep(AstScope* nodep) { m_scopep = nodep; } - string rtnTypeVoid() const { return ((m_rtnType == "") ? "void" : m_rtnType); } - bool dontCombine() const { return m_dontCombine || isTrace() || entryPoint(); } - void dontCombine(bool flag) { m_dontCombine = flag; } - bool dontInline() const { return dontCombine() || slow() || funcPublic(); } - bool declPrivate() const { return m_declPrivate; } - void declPrivate(bool flag) { m_declPrivate = flag; } - bool isFinal() const { return m_isFinal; } - void isFinal(bool flag) { m_isFinal = flag; } - bool slow() const { return m_slow; } - void slow(bool flag) { m_slow = flag; } - bool funcPublic() const { return m_funcPublic; } - void funcPublic(bool flag) { m_funcPublic = flag; } - void argTypes(const string& str) { m_argTypes = str; } - string argTypes() const { return m_argTypes; } - void ctorInits(const string& str) { m_ctorInits = str; } - string ctorInits() const { return m_ctorInits; } - void ifdef(const string& str) { m_ifdef = str; } - string ifdef() const { return m_ifdef; } - bool isConstructor() const { return m_isConstructor; } - void isConstructor(bool flag) { m_isConstructor = flag; } - bool isDestructor() const { return m_isDestructor; } - void isDestructor(bool flag) { m_isDestructor = flag; } - bool isMethod() const { return m_isMethod; } - void isMethod(bool flag) { m_isMethod = flag; } - bool isLoose() const { return m_isLoose; } - void isLoose(bool flag) { m_isLoose = flag; } - bool isProperMethod() const { return isMethod() && !isLoose(); } - bool isInline() const { return m_isInline; } - void isInline(bool flag) { m_isInline = flag; } - bool isVirtual() const { return m_isVirtual; } - void isVirtual(bool flag) { m_isVirtual = flag; } - bool entryPoint() const { return m_entryPoint; } - void entryPoint(bool flag) { m_entryPoint = flag; } - bool pure() const { return m_pure; } - void pure(bool flag) { m_pure = flag; } - bool dpiContext() const { return m_dpiContext; } - void dpiContext(bool flag) { m_dpiContext = flag; } - bool dpiExportDispatcher() const { return m_dpiExportDispatcher; } - void dpiExportDispatcher(bool flag) { m_dpiExportDispatcher = flag; } - bool dpiExportImpl() const { return m_dpiExportImpl; } - void dpiExportImpl(bool flag) { m_dpiExportImpl = flag; } - bool dpiImportPrototype() const { return m_dpiImportPrototype; } - void dpiImportPrototype(bool flag) { m_dpiImportPrototype = flag; } - bool dpiImportWrapper() const { return m_dpiImportWrapper; } - void dpiImportWrapper(bool flag) { m_dpiImportWrapper = flag; } - void dpiTraceInit(bool flag) { m_dpiTraceInit = flag; } - bool dpiTraceInit() const { return m_dpiTraceInit; } - // - // If adding node accessors, see below emptyBody - AstNode* argsp() const { return op1p(); } - void addArgsp(AstNode* nodep) { addOp1p(nodep); } - AstNode* initsp() const { return op2p(); } - void addInitsp(AstNode* nodep) { addOp2p(nodep); } - AstNode* stmtsp() const { return op3p(); } - void addStmtsp(AstNode* nodep) { addOp3p(nodep); } - AstNode* finalsp() const { return op4p(); } - void addFinalsp(AstNode* nodep) { addOp4p(nodep); } - // Special methods - bool emptyBody() const { - return argsp() == nullptr && initsp() == nullptr && stmtsp() == nullptr - && finalsp() == nullptr; - } -}; - -class AstCCall final : public AstNodeCCall { - // C++ function call - // Parents: Anything above a statement - // Children: Args to the function - - string m_selfPointer; // Output code object pointer (e.g.: 'this') - -public: - AstCCall(FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) - : ASTGEN_SUPER_CCall(fl, funcp, argsp) {} - ASTNODE_NODE_FUNCS(CCall) - - string selfPointer() const { return m_selfPointer; } - void selfPointer(const string& value) { m_selfPointer = value; } - string selfPointerProtect(bool useSelfForThis) const; -}; - -class AstCMethodCall final : public AstNodeCCall { - // C++ method call - // Parents: Anything above a statement - // Children: Args to the function -public: - AstCMethodCall(FileLine* fl, AstNode* fromp, AstCFunc* funcp, AstNode* argsp = nullptr) - : ASTGEN_SUPER_CMethodCall(fl, funcp, argsp) { - setOp1p(fromp); - } - ASTNODE_NODE_FUNCS(CMethodCall) - virtual const char* broken() const override { - BROKEN_BASE_RTN(AstNodeCCall::broken()); - BROKEN_RTN(!fromp()); - return nullptr; - } - AstNode* fromp() const { - return op1p(); - } // op1 = Extracting what (nullptr=TBD during parsing) - void fromp(AstNode* nodep) { setOp1p(nodep); } -}; - -class AstCNew final : public AstNodeCCall { - // C++ new() call - // Parents: Anything above an expression - // Children: Args to the function -public: - AstCNew(FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) - : ASTGEN_SUPER_CNew(fl, funcp, argsp) { - statement(false); - } - virtual bool hasDType() const override { return true; } - ASTNODE_NODE_FUNCS(CNew) -}; - -class AstCReturn final : public AstNodeStmt { - // C++ return from a function - // Parents: CFUNC/statement - // Children: Math -public: - AstCReturn(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER_CReturn(fl) { - setOp1p(lhsp); - } - ASTNODE_NODE_FUNCS(CReturn) - virtual int instrCount() const override { return widthInstrs(); } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - // - AstNode* lhsp() const { return op1p(); } -}; - -class AstCMath final : public AstNodeMath { -private: - const bool m_cleanOut; - bool m_pure; // Pure optimizable -public: - // Emit C textual math function (like AstUCFunc) - AstCMath(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER_CMath(fl) - , m_cleanOut{true} - , m_pure{false} { - addOp1p(exprsp); - dtypeFrom(exprsp); - } - AstCMath(FileLine* fl, const string& textStmt, int setwidth, bool cleanOut = true) - : ASTGEN_SUPER_CMath(fl) - , m_cleanOut{cleanOut} - , m_pure{true} { - addNOp1p(new AstText(fl, textStmt, true)); - if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); - } - ASTNODE_NODE_FUNCS(CMath) - virtual bool isGateOptimizable() const override { return m_pure; } - virtual bool isPredictOptimizable() const override { return m_pure; } - virtual bool cleanOut() const override { return m_cleanOut; } - virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } - virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - void addBodysp(AstNode* nodep) { addNOp1p(nodep); } - AstNode* bodysp() const { return op1p(); } // op1 = expressions to print - bool pure() const { return m_pure; } - void pure(bool flag) { m_pure = flag; } -}; - -class AstCReset final : public AstNodeStmt { - // Reset variable at startup -public: - AstCReset(FileLine* fl, AstVarRef* exprsp) - : ASTGEN_SUPER_CReset(fl) { - addNOp1p(exprsp); - } - ASTNODE_NODE_FUNCS(CReset) - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - AstVarRef* varrefp() const { return VN_AS(op1p(), VarRef); } // op1 = varref to reset -}; - -class AstCStmt final : public AstNodeStmt { - // Emit C statement -public: - AstCStmt(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER_CStmt(fl) { - addNOp1p(exprsp); - } - AstCStmt(FileLine* fl, const string& textStmt) - : ASTGEN_SUPER_CStmt(fl) { - addNOp1p(new AstText(fl, textStmt, true)); - } - ASTNODE_NODE_FUNCS(CStmt) - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool same(const AstNode* /*samep*/) const override { return true; } - void addBodysp(AstNode* nodep) { addNOp1p(nodep); } - AstNode* bodysp() const { return op1p(); } // op1 = expressions to print -}; - -class AstCUse final : public AstNode { - // C++ use of a class or #include; indicates need of forward declaration - // Parents: NODEMODULE -private: - const VUseType m_useType; // What sort of use this is - const string m_name; - -public: - AstCUse(FileLine* fl, VUseType useType, const string& name) - : ASTGEN_SUPER_CUse(fl) - , m_useType{useType} - , m_name{name} {} - ASTNODE_NODE_FUNCS(CUse) - virtual void dump(std::ostream& str = std::cout) const override; - virtual string name() const override { return m_name; } - VUseType useType() const { return m_useType; } -}; - -class AstMTaskBody final : public AstNode { - // Hold statements for each MTask -private: - ExecMTask* m_execMTaskp = nullptr; - -public: - explicit AstMTaskBody(FileLine* fl) - : ASTGEN_SUPER_MTaskBody(fl) {} - ASTNODE_NODE_FUNCS(MTaskBody); - virtual const char* broken() const override { - BROKEN_RTN(!m_execMTaskp); - return nullptr; - } - AstNode* stmtsp() const { return op1p(); } - void addStmtsp(AstNode* nodep) { addOp1p(nodep); } - void addStmtsFirstp(AstNode* nodep) { - if (stmtsp()) { - stmtsp()->addHereThisAsNext(nodep); - } else { - addStmtsp(nodep); - } - } - ExecMTask* execMTaskp() const { return m_execMTaskp; } - void execMTaskp(ExecMTask* execMTaskp) { m_execMTaskp = execMTaskp; } - virtual void dump(std::ostream& str = std::cout) const override; -}; - -class AstExecGraph final : public AstNode { - // For parallel execution, this node contains a dependency graph. Each - // vertex in the graph is an ExecMTask, which contains a body for the - // mtask (an AstMTaskBody), which contains sequentially executed statements. - // - // The AstMTaskBody nodes are also children of this node, so we can visit - // them without traversing the graph. -private: - V3Graph* const m_depGraphp; // contains ExecMTask vertices - const string m_name; // Name of this AstExecGraph (for uniqueness at code generation) - -public: - explicit AstExecGraph(FileLine* fl, const string& name); - ASTNODE_NODE_FUNCS_NO_DTOR(ExecGraph) - virtual ~AstExecGraph() override; - virtual const char* broken() const override { - BROKEN_RTN(!m_depGraphp); - return nullptr; - } - virtual string name() const override { return m_name; } - V3Graph* depGraphp() { return m_depGraphp; } - const V3Graph* depGraphp() const { return m_depGraphp; } - // op1: The mtask bodies - AstMTaskBody* mTaskBodiesp() const { return VN_AS(op1p(), MTaskBody); } - void addMTaskBodyp(AstMTaskBody* bodyp) { addOp1p(bodyp); } - // op2: In later phases, the statements that start the parallel execution - void addStmtsp(AstNode* stmtp) { addOp2p(stmtp); } -}; - -class AstSplitPlaceholder final : public AstNode { -public: - // Dummy node used within V3Split; never exists outside of V3Split. - explicit AstSplitPlaceholder(FileLine* fl) - : ASTGEN_SUPER_SplitPlaceholder(fl) {} - ASTNODE_NODE_FUNCS(SplitPlaceholder) -}; - -//###################################################################### -// Right below top - -class AstTypeTable final : public AstNode { - // Container for hash of standard data types - // Children: NODEDTYPEs - AstEmptyQueueDType* m_emptyQueuep = nullptr; - AstQueueDType* m_queueIndexp = nullptr; - AstVoidDType* m_voidp = nullptr; - AstBasicDType* m_basicps[VBasicDTypeKwd::_ENUM_MAX]{}; - // - using DetailedMap = std::map; - DetailedMap m_detailedMap; - -public: - explicit AstTypeTable(FileLine* fl); - ASTNODE_NODE_FUNCS(TypeTable) - virtual bool maybePointedTo() const override { return true; } - virtual const char* broken() const override { - BROKEN_RTN(m_emptyQueuep && !m_emptyQueuep->brokeExists()); - BROKEN_RTN(m_queueIndexp && !m_queueIndexp->brokeExists()); - BROKEN_RTN(m_voidp && !m_voidp->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { V3ERROR_NA; } - AstNodeDType* typesp() const { return VN_AS(op1p(), NodeDType); } // op1 = List of dtypes - void addTypesp(AstNodeDType* nodep) { addOp1p(nodep); } - AstBasicDType* findBasicDType(FileLine* fl, VBasicDTypeKwd kwd); - AstBasicDType* findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd, int width, int widthMin, - VSigning numeric); - AstBasicDType* findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd, const VNumRange& range, - int widthMin, VSigning numeric); - AstBasicDType* findInsertSameDType(AstBasicDType* nodep); - AstEmptyQueueDType* findEmptyQueueDType(FileLine* fl); - AstQueueDType* findQueueIndexDType(FileLine* fl); - AstVoidDType* findVoidDType(FileLine* fl); - void clearCache(); - void repairCache(); - virtual void dump(std::ostream& str = std::cout) const override; -}; - -class AstConstPool final : public AstNode { - // Container for const static data - std::unordered_multimap m_tables; // Constant tables (unpacked arrays) - std::unordered_multimap m_consts; // Constant tables (scalars) - AstModule* const m_modp; // The Module holding the Scope below ... - AstScope* const m_scopep; // Scope holding the constant variables - - AstVarScope* createNewEntry(const string& name, AstNode* initp); - -public: - explicit AstConstPool(FileLine* fl); - ASTNODE_NODE_FUNCS(ConstPool) - virtual bool maybePointedTo() const override { return true; } - virtual const char* broken() const override { - BROKEN_RTN(m_modp && !m_modp->brokeExists()); - BROKEN_RTN(m_scopep && !m_scopep->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { V3ERROR_NA; } - AstModule* modp() const { return m_modp; } - - // Find a table (unpacked array) within the constant pool which is initialized with the - // given value, or create one if one does not already exists. The returned VarScope *might* - // have a different dtype than the given initp->dtypep(), including a different element type, - // but it will always have the same size and element width. In contexts where this matters, - // the caller must handle the dtype difference as appropriate. - AstVarScope* findTable(AstInitArray* initp); - // Find a constant within the constant pool which is initialized with the given value, or - // create one if one does not already exists. If 'mergeDType' is true, then the returned - // VarScope *might* have a different type than the given initp->dtypep(). In contexts where - // this matters, the caller must handle the dtype difference as appropriate. If 'mergeDType' is - // false, the returned VarScope will have _->dtypep()->sameTree(initp->dtypep()) return true. - AstVarScope* findConst(AstConst* initp, bool mergeDType); -}; - -//###################################################################### -// Top - -class AstNetlist final : public AstNode { - // All modules are under this single top node. - // Parents: none - // Children: MODULEs & CFILEs -private: - AstTypeTable* const m_typeTablep; // Reference to top type table, for faster lookup - AstConstPool* const m_constPoolp; // Reference to constant pool, for faster lookup - AstPackage* m_dollarUnitPkgp = nullptr; // $unit - AstCFunc* m_evalp = nullptr; // The '_eval' function - AstVarScope* m_dpiExportTriggerp = nullptr; // The DPI export trigger variable - AstTopScope* m_topScopep = nullptr; // The singleton AstTopScope under the top module - VTimescale m_timeunit; // Global time unit - VTimescale m_timeprecision; // Global time precision - bool m_changeRequest = false; // Have _change_request method - bool m_timescaleSpecified = false; // Input HDL specified timescale - uint32_t m_nextFreeMTaskID = 1; // Next unique MTask ID within netlist - // starts at 1 so 0 means no MTask ID - uint32_t m_nextFreeMTaskProfilingID = 0; // Next unique ID to use for PGO -public: - AstNetlist(); - ASTNODE_NODE_FUNCS(Netlist) - virtual const char* broken() const override { - BROKEN_RTN(m_typeTablep && !m_typeTablep->brokeExists()); - BROKEN_RTN(m_constPoolp && !m_constPoolp->brokeExists()); - BROKEN_RTN(m_dollarUnitPkgp && !m_dollarUnitPkgp->brokeExists()); - BROKEN_RTN(m_evalp && !m_evalp->brokeExists()); - BROKEN_RTN(m_dpiExportTriggerp && !m_dpiExportTriggerp->brokeExists()); - BROKEN_RTN(m_topScopep && !m_topScopep->brokeExists()); - return nullptr; - } - virtual void cloneRelink() override { V3ERROR_NA; } - virtual string name() const override { return "$root"; } - virtual void dump(std::ostream& str) const override; - AstNodeModule* modulesp() const { // op1 = List of modules - return VN_AS(op1p(), NodeModule); - } - AstNodeModule* topModulep() const { // Top module in hierarchy - return modulesp(); // First one in the list, for now - } - void addModulep(AstNodeModule* modulep) { addOp1p(modulep); } - AstNodeFile* filesp() const { return VN_AS(op2p(), NodeFile); } // op2 = List of files - void addFilesp(AstNodeFile* filep) { addOp2p(filep); } - void addMiscsp(AstNode* nodep) { addOp3p(nodep); } - AstTypeTable* typeTablep() { return m_typeTablep; } - void changeRequest(bool specified) { m_changeRequest = specified; } - bool changeRequest() const { return m_changeRequest; } - AstConstPool* constPoolp() { return m_constPoolp; } - AstPackage* dollarUnitPkgp() const { return m_dollarUnitPkgp; } - AstPackage* dollarUnitPkgAddp() { - if (!m_dollarUnitPkgp) { - m_dollarUnitPkgp = new AstPackage(fileline(), AstPackage::dollarUnitName()); - // packages are always libraries; don't want to make them a "top" - m_dollarUnitPkgp->inLibrary(true); - m_dollarUnitPkgp->modTrace(false); // may reconsider later - m_dollarUnitPkgp->internal(true); - addModulep(m_dollarUnitPkgp); - } - return m_dollarUnitPkgp; - } - AstCFunc* evalp() const { return m_evalp; } - void evalp(AstCFunc* evalp) { m_evalp = evalp; } - AstVarScope* dpiExportTriggerp() const { return m_dpiExportTriggerp; } - void dpiExportTriggerp(AstVarScope* varScopep) { m_dpiExportTriggerp = varScopep; } - AstTopScope* topScopep() const { return m_topScopep; } - void createTopScope(AstScope* scopep) { - UASSERT(scopep, "Must not be nullptr"); - UASSERT_OBJ(!m_topScopep, scopep, "TopScope already exits"); - m_topScopep = new AstTopScope{scopep->modp()->fileline(), scopep}; - scopep->modp()->addStmtp(v3Global.rootp()->topScopep()); - } - VTimescale timeunit() const { return m_timeunit; } - void timeunit(const VTimescale& value) { m_timeunit = value; } - VTimescale timeprecision() const { return m_timeprecision; } - void timeInit() { - m_timeunit = v3Global.opt.timeDefaultUnit(); - m_timeprecision = v3Global.opt.timeDefaultPrec(); - } - void timeprecisionMerge(FileLine*, const VTimescale& value); - void timescaleSpecified(bool specified) { m_timescaleSpecified = specified; } - bool timescaleSpecified() const { return m_timescaleSpecified; } - uint32_t allocNextMTaskID() { return m_nextFreeMTaskID++; } - uint32_t allocNextMTaskProfilingID() { return m_nextFreeMTaskProfilingID++; } - uint32_t usedMTaskProfilingIDs() const { return m_nextFreeMTaskProfilingID; } -}; - -//###################################################################### - -#include "V3AstInlines.h" - -#endif // Guard diff --git a/src/V3AstUserAllocator.h b/src/V3AstUserAllocator.h index 76ec4fc5d..1a7f55a46 100644 --- a/src/V3AstUserAllocator.h +++ b/src/V3AstUserAllocator.h @@ -35,7 +35,7 @@ class AstUserAllocatorBase VL_NOT_FINAL { private: std::vector m_allocated; - inline T_Data* getUserp(const T_Node* nodep) const { + T_Data* getUserp(const T_Node* nodep) const { if VL_CONSTEXPR_CXX17 (T_UserN == 1) { const VNUser user = nodep->user1u(); return user.to(); @@ -54,17 +54,17 @@ private: } } - inline void setUserp(T_Node* nodep, T_Data* userp) const { + void setUserp(T_Node* nodep, T_Data* userp) const { if VL_CONSTEXPR_CXX17 (T_UserN == 1) { - nodep->user1u(VNUser(userp)); + nodep->user1u(VNUser{userp}); } else if VL_CONSTEXPR_CXX17 (T_UserN == 2) { - nodep->user2u(VNUser(userp)); + nodep->user2u(VNUser{userp}); } else if VL_CONSTEXPR_CXX17 (T_UserN == 3) { - nodep->user3u(VNUser(userp)); + nodep->user3u(VNUser{userp}); } else if VL_CONSTEXPR_CXX17 (T_UserN == 4) { - nodep->user4u(VNUser(userp)); + nodep->user4u(VNUser{userp}); } else { - nodep->user5u(VNUser(userp)); + nodep->user5u(VNUser{userp}); } } diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index 0e4176739..4cdb480e6 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -35,6 +35,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### class BeginState final { @@ -70,7 +72,6 @@ private: int m_ifDepth = 0; // Current if depth // METHODS - VL_DEBUG_FUNC; // Declare debug() string dot(const string& a, const string& b) { if (a == "") return b; @@ -85,7 +86,7 @@ private: string::size_type pos; while ((pos = dottedname.find("__DOT__")) != string::npos) { const string ident = dottedname.substr(0, pos); - dottedname = dottedname.substr(pos + strlen("__DOT__")); + dottedname = dottedname.substr(pos + std::strlen("__DOT__")); if (nodep->name() != "") { m_displayScope = dot(m_displayScope, ident); m_namedScope = dot(m_namedScope, ident); @@ -115,19 +116,19 @@ private: } } else { // Move to module - m_modp->addStmtp(nodep); + m_modp->addStmtsp(nodep); } } // VISITORS - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { VL_RESTORER(m_modp); { m_modp = nodep; iterateChildren(nodep); } } - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstNodeFTask* nodep) override { UINFO(8, " " << nodep << endl); // Rename it if (m_unnamedScope != "") { @@ -162,7 +163,7 @@ private: m_ftaskp = nullptr; } } - virtual void visit(AstBegin* nodep) override { + void visit(AstBegin* nodep) override { // Begin blocks were only useful in variable creation, change names and delete UINFO(8, " " << nodep << endl); VL_RESTORER(m_displayScope); @@ -177,11 +178,7 @@ private: AstNode* addsp = nullptr; if (AstNode* const stmtsp = nodep->stmtsp()) { stmtsp->unlinkFrBackWithNext(); - if (addsp) { - addsp = addsp->addNextNull(stmtsp); - } else { - addsp = stmtsp; - } + addsp = AstNode::addNext(addsp, stmtsp); } if (addsp) { nodep->replaceWith(addsp); @@ -191,7 +188,7 @@ private: VL_DO_DANGLING(pushDeletep(nodep), nodep); } } - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { if (m_unnamedScope != "") { // Rename it nodep->name(dot(m_unnamedScope, nodep->name())); @@ -200,7 +197,7 @@ private: liftNode(nodep); } } - virtual void visit(AstTypedef* nodep) override { + void visit(AstTypedef* nodep) override { if (m_unnamedScope != "") { // Rename it nodep->name(dot(m_unnamedScope, nodep->name())); @@ -209,7 +206,7 @@ private: liftNode(nodep); } } - virtual void visit(AstCell* nodep) override { + void visit(AstCell* nodep) override { UINFO(8, " CELL " << nodep << endl); if (m_namedScope != "") { m_statep->userMarkChanged(nodep); @@ -218,18 +215,18 @@ private: UINFO(8, " rename to " << nodep->name() << endl); // Move to module nodep->unlinkFrBack(); - m_modp->addStmtp(nodep); + m_modp->addStmtsp(nodep); } iterateChildren(nodep); } - virtual void visit(AstVarXRef* nodep) override { + void visit(AstVarXRef* nodep) override { UINFO(9, " VARXREF " << nodep << endl); if (m_namedScope != "" && nodep->inlinedDots() == "" && !m_ftaskp) { nodep->inlinedDots(m_namedScope); UINFO(9, " rescope to " << nodep << endl); } } - virtual void visit(AstScopeName* nodep) override { + void visit(AstScopeName* nodep) override { // If there's a %m in the display text, we add a special node that will contain the name() // Similar code in V3Inline if (nodep->user1SetOnce()) return; // Don't double-add text's @@ -237,20 +234,20 @@ private: const string scname = nodep->forFormat() ? m_displayScope : m_namedScope; if (!scname.empty()) { // To keep correct visual order, must add before other Text's - AstNode* const afterp = nodep->scopeAttrp(); + AstText* const afterp = nodep->scopeAttrp(); if (afterp) afterp->unlinkFrBackWithNext(); - nodep->scopeAttrp(new AstText{nodep->fileline(), string("__DOT__") + scname}); - if (afterp) nodep->scopeAttrp(afterp); + nodep->addScopeAttrp(new AstText{nodep->fileline(), string("__DOT__") + scname}); + if (afterp) nodep->addScopeAttrp(afterp); } iterateChildren(nodep); } - virtual void visit(AstCoverDecl* nodep) override { + void visit(AstCoverDecl* nodep) override { // Don't need to fix path in coverage statements, they're not under // any BEGINs, but V3Coverage adds them all under the module itself. iterateChildren(nodep); } // VISITORS - LINT CHECK - virtual void visit(AstIf* nodep) override { // not AstNodeIf; other types not covered + void visit(AstIf* nodep) override { // not AstNodeIf; other types not covered // Check IFDEPTH warning - could be in other transform files if desire VL_RESTORER(m_ifDepth); if (m_ifDepth == -1 || v3Global.opt.ifDepth() < 1) { // Turned off @@ -264,7 +261,7 @@ private: } iterateChildren(nodep); } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -272,7 +269,7 @@ public: : m_statep{statep} { iterate(nodep); } - virtual ~BeginVisitor() override = default; + ~BeginVisitor() override = default; }; //###################################################################### @@ -285,21 +282,21 @@ private: // AstNodeFTask::user1p // Node replaced, rename it // VISITORS - virtual void visit(AstNodeFTaskRef* nodep) override { + void visit(AstNodeFTaskRef* nodep) override { if (nodep->taskp()->user1()) { // It was converted UINFO(9, " relinkFTask " << nodep << endl); nodep->name(nodep->taskp()->name()); } iterateChildren(nodep); } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { if (nodep->varp()->user1()) { // It was converted UINFO(9, " relinVarRef " << nodep << endl); nodep->name(nodep->varp()->name()); } iterateChildren(nodep); } - virtual void visit(AstIfaceRefDType* nodep) override { + void visit(AstIfaceRefDType* nodep) override { // May have changed cell names // TypeTable is always after all modules, so names are stable UINFO(8, " IFACEREFDTYPE " << nodep << endl); @@ -308,12 +305,12 @@ private: iterateChildren(nodep); } //-------------------- - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS BeginRelinkVisitor(AstNetlist* nodep, BeginState*) { iterate(nodep); } - virtual ~BeginRelinkVisitor() override = default; + ~BeginRelinkVisitor() override = default; }; //###################################################################### @@ -326,5 +323,5 @@ void V3Begin::debeginAll(AstNetlist* nodep) { { BeginVisitor{nodep, &state}; } if (state.anyFuncInBegin()) { BeginRelinkVisitor{nodep, &state}; } } // Destruct before checking - V3Global::dumpCheckGlobalTree("begin", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("begin", 0, dumpTree() >= 3); } diff --git a/src/V3Branch.cpp b/src/V3Branch.cpp index 51c749eb4..0cf4acda9 100644 --- a/src/V3Branch.cpp +++ b/src/V3Branch.cpp @@ -33,6 +33,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Branch state, as a visitor of each AstNode @@ -49,7 +51,6 @@ private: std::vector m_cfuncsp; // List of all tasks // METHODS - VL_DEBUG_FUNC; // Declare debug() void reset() { m_likely = false; @@ -63,14 +64,14 @@ private: } // VISITORS - virtual void visit(AstNodeIf* nodep) override { + void visit(AstNodeIf* nodep) override { UINFO(4, " IF: " << nodep << endl); VL_RESTORER(m_likely); VL_RESTORER(m_unlikely); { // Do if reset(); - iterateAndNextNull(nodep->ifsp()); + iterateAndNextNull(nodep->thensp()); const int ifLikely = m_likely; const int ifUnlikely = m_unlikely; // Do else @@ -87,17 +88,17 @@ private: } // else leave unknown } } - virtual void visit(AstNodeCCall* nodep) override { + void visit(AstNodeCCall* nodep) override { checkUnlikely(nodep); nodep->funcp()->user1Inc(); iterateChildren(nodep); } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { checkUnlikely(nodep); m_cfuncsp.push_back(nodep); iterateChildren(nodep); } - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { checkUnlikely(nodep); iterateChildren(nodep); } @@ -116,7 +117,7 @@ public: iterateChildren(nodep); calc_tasks(); } - virtual ~BranchVisitor() override = default; + ~BranchVisitor() override = default; }; //###################################################################### diff --git a/src/V3Broken.cpp b/src/V3Broken.cpp index 6f1f906e8..d039e593b 100644 --- a/src/V3Broken.cpp +++ b/src/V3Broken.cpp @@ -36,6 +36,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Generation counter for AstNode::m_brokenState @@ -132,8 +134,8 @@ private: public: // METHODS void clear() { m_linkable.clear(); } - inline void addLinkable(const AstNode* nodep) { m_linkable.emplace(nodep); } - inline bool isLinkable(const AstNode* nodep) const { return m_linkable.count(nodep) != 0; } + void addLinkable(const AstNode* nodep) { m_linkable.emplace(nodep); } + bool isLinkable(const AstNode* nodep) const { return m_linkable.count(nodep) != 0; } } s_linkableTable; bool V3Broken::isLinkable(const AstNode* nodep) { return s_linkableTable.isLinkable(nodep); } @@ -214,27 +216,27 @@ private: } return false; } - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { processAndIterate(nodep); UASSERT_OBJ(!(v3Global.assertDTypesResolved() && nodep->brokeLhsMustBeLvalue() && VN_IS(nodep->lhsp(), NodeVarRef) && !VN_AS(nodep->lhsp(), NodeVarRef)->access().isWriteOrRW()), nodep, "Assignment LHS is not an lvalue"); } - virtual void visit(AstRelease* nodep) override { + void visit(AstRelease* nodep) override { processAndIterate(nodep); UASSERT_OBJ(!(v3Global.assertDTypesResolved() && VN_IS(nodep->lhsp(), NodeVarRef) && !VN_AS(nodep->lhsp(), NodeVarRef)->access().isWriteOrRW()), nodep, "Release LHS is not an lvalue"); } - virtual void visit(AstScope* nodep) override { + void visit(AstScope* nodep) override { VL_RESTORER(m_inScope); { m_inScope = true; processAndIterate(nodep); } } - virtual void visit(AstNodeVarRef* nodep) override { + void visit(AstNodeVarRef* nodep) override { processAndIterate(nodep); // m_inScope because some Vars have initial variable references without scopes // This might false fire with some debug flags, as not certain we don't have temporary @@ -252,7 +254,7 @@ private: } } } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { UASSERT_OBJ(!m_cfuncp, nodep, "Nested AstCFunc"); m_cfuncp = nodep; m_localVars.clear(); @@ -270,14 +272,14 @@ private: m_cfuncp = nullptr; } - virtual void visit(AstNodeIf* nodep) override { + void visit(AstNodeIf* nodep) override { // Each branch is a separate local variable scope pushLocalScope(); processEnter(nodep); processAndIterate(nodep->condp()); - if (AstNode* const ifsp = nodep->ifsp()) { + if (AstNode* const thensp = nodep->thensp()) { pushLocalScope(); - processAndIterateList(ifsp); + processAndIterateList(thensp); popLocalScope(); } if (AstNode* const elsesp = nodep->elsesp()) { @@ -288,21 +290,21 @@ private: processExit(nodep); popLocalScope(); } - virtual void visit(AstNodeStmt* nodep) override { + void visit(AstNodeStmt* nodep) override { // For local variable checking act as if any statement introduces a new scope. // This is aggressive but conservatively correct. pushLocalScope(); processAndIterate(nodep); popLocalScope(); } - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { processAndIterate(nodep); if (m_cfuncp) { m_localVars.insert(nodep); m_localsStack.back().insert(nodep); } } - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { // Process not just iterate processAndIterate(nodep); } @@ -310,7 +312,7 @@ private: public: // CONSTRUCTORS explicit BrokenCheckVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~BrokenCheckVisitor() override = default; + ~BrokenCheckVisitor() override = default; }; //###################################################################### diff --git a/src/V3CCtors.cpp b/src/V3CCtors.cpp index f28e959fc..c4af9097e 100644 --- a/src/V3CCtors.cpp +++ b/src/V3CCtors.cpp @@ -35,6 +35,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + class VCtorType final { public: enum en : uint8_t { MODULE, CLASS, COVERAGE }; @@ -44,7 +46,7 @@ private: public: // cppcheck-suppress noExplicitConstructor - inline VCtorType(en _e) + constexpr VCtorType(en _e) : m_e{_e} {} bool isClass() const { return m_e == CLASS; } bool isCoverage() const { return m_e == COVERAGE; } @@ -77,7 +79,7 @@ private: if (!preventUnusedStmt.empty()) { funcp->addStmtsp(new AstCStmt{m_modp->fileline(), preventUnusedStmt}); } - m_modp->addStmtp(funcp); + m_modp->addStmtsp(funcp); m_numStmts = 0; return funcp; } @@ -136,7 +138,7 @@ void V3CCtors::evalAsserts() { funcp->isLoose(true); funcp->slow(false); funcp->ifdef("VL_DEBUG"); - modp->addStmtp(funcp); + modp->addStmtsp(funcp); for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) { if (AstVar* const varp = VN_CAST(np, Var)) { if (varp->isPrimaryInish() && !varp->isSc()) { @@ -209,7 +211,7 @@ void V3CCtors::cctorsAll() { // If can be referred to by base pointer, need virtual delete funcp->isVirtual(classp->isExtended()); funcp->slow(false); - modp->addStmtp(funcp); + modp->addStmtsp(funcp); } } } diff --git a/src/V3CUse.cpp b/src/V3CUse.cpp index 2d301567e..11eb84957 100644 --- a/src/V3CUse.cpp +++ b/src/V3CUse.cpp @@ -32,6 +32,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Visit within a module all nodes and data types they reference, finding @@ -51,13 +53,13 @@ class CUseVisitor final : public VNVisitor { void addNewUse(AstNode* nodep, VUseType useType, const string& name) { if (m_didUse.emplace(useType, name).second) { AstCUse* const newp = new AstCUse{nodep->fileline(), useType, name}; - m_modp->addStmtp(newp); + m_modp->addStmtsp(newp); UINFO(8, "Insert " << newp << endl); } } // VISITORS - virtual void visit(AstClassRefDType* nodep) override { + void visit(AstClassRefDType* nodep) override { if (nodep->user1SetOnce()) return; // Process once if (!m_impOnly) addNewUse(nodep, VUseType::INT_FWD_CLASS, nodep->classp()->name()); // Need to include extends() when we implement, but no need for pointers to know @@ -67,17 +69,17 @@ class CUseVisitor final : public VNVisitor { iterateChildren(nodep->classp()); // This also gets all extend classes } } - virtual void visit(AstNodeDType* nodep) override { + void visit(AstNodeDType* nodep) override { if (nodep->user1SetOnce()) return; // Process once if (nodep->virtRefDTypep()) iterate(nodep->virtRefDTypep()); if (nodep->virtRefDType2p()) iterate(nodep->virtRefDType2p()); } - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { if (nodep->user1SetOnce()) return; // Process once if (nodep->dtypep() && !nodep->dtypep()->user1()) iterate(nodep->dtypep()); iterateChildren(nodep); } - virtual void visit(AstCell* nodep) override { + void visit(AstCell* nodep) override { if (nodep->user1SetOnce()) return; // Process once // Currently no IMP_INCLUDE because we include __Syms which has them all addNewUse(nodep, VUseType::INT_FWD_CLASS, nodep->modp()->name()); @@ -90,7 +92,7 @@ public: : m_modp(modp) { iterate(modp); } - virtual ~CUseVisitor() override = default; + ~CUseVisitor() override = default; VL_UNCOPYABLE(CUseVisitor); }; @@ -106,5 +108,5 @@ void V3CUse::cUseAll() { // for each output file and put under that CUseVisitor{modp}; } - V3Global::dumpCheckGlobalTree("cuse", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("cuse", 0, dumpTree() >= 3); } diff --git a/src/V3Case.cpp b/src/V3Case.cpp index c8a2e639f..258f76e0d 100644 --- a/src/V3Case.cpp +++ b/src/V3Case.cpp @@ -45,6 +45,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + #define CASE_OVERLAP_WIDTH 16 // Maximum width we can check for overlaps in #define CASE_BARF 999999 // Magic width when non-constant #define CASE_ENCODER_GROUP_DEPTH 8 // Levels of priority to be ORed together in top IF tree @@ -57,9 +59,8 @@ private: = nullptr; // Under a CASE value node, if so the relevant case statement // METHODS - VL_DEBUG_FUNC; // Declare debug() - virtual void visit(AstNodeCase* nodep) override { + void visit(AstNodeCase* nodep) override { if (VN_IS(nodep, Case) && VN_AS(nodep, Case)->casex()) { nodep->v3warn(CASEX, "Suggest casez (with ?'s) in place of casex (with X's)"); } @@ -86,7 +87,7 @@ private: m_caseExprp = nullptr; } } - virtual void visit(AstConst* nodep) override { + void visit(AstConst* nodep) override { // See also neverItem if (m_caseExprp && nodep->num().isFourState()) { if (VN_IS(m_caseExprp, GenCase)) { @@ -107,12 +108,12 @@ private: } } } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit CaseLintVisitor(AstNodeCase* nodep) { iterate(nodep); } - virtual ~CaseLintVisitor() override = default; + ~CaseLintVisitor() override = default; }; //###################################################################### @@ -138,7 +139,6 @@ private: std::array m_valueItem; // METHODS - VL_DEBUG_FUNC; // Declare debug() bool isCaseTreeFast(AstCase* nodep) { int width = 0; @@ -245,7 +245,7 @@ private: // Convert valueItem from AstCaseItem* to the expression // Not done earlier, as we may now have a nullptr because it's just a ";" NOP branch for (uint32_t i = 0; i < numCases; ++i) { - m_valueItem[i] = VN_AS(m_valueItem[i], CaseItem)->bodysp(); + m_valueItem[i] = VN_AS(m_valueItem[i], CaseItem)->stmtsp(); } return true; // All is fine } @@ -346,7 +346,7 @@ private: itemp = VN_AS(itemp->nextp(), CaseItem)) { if (!itemp->condsp()) { // Default clause. Just make true, we'll optimize it away later - itemp->condsp(new AstConst(itemp->fileline(), AstConst::BitTrue())); + itemp->addCondsp(new AstConst(itemp->fileline(), AstConst::BitTrue())); hadDefault = true; } else { // Expressioned clause @@ -397,7 +397,7 @@ private: } } // Replace expression in tree - itemp->condsp(ifexprp); + itemp->addCondsp(ifexprp); } } VL_DO_DANGLING(cexprp->deleteTree(), cexprp); @@ -420,7 +420,7 @@ private: AstIf* itemnextp = nullptr; for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp = VN_AS(itemp->nextp(), CaseItem)) { - AstNode* const istmtsp = itemp->bodysp(); // Maybe null -- no action. + AstNode* const istmtsp = itemp->stmtsp(); // Maybe null -- no action. if (istmtsp) istmtsp->unlinkFrBackWithNext(); // Expressioned clause AstNode* const ifexprp = itemp->condsp()->unlinkFrBack(); @@ -452,7 +452,7 @@ private: if (itemnextp) { itemnextp->addElsesp(newp); } else { - groupnextp->addIfsp(newp); // First in a new group + groupnextp->addThensp(newp); // First in a new group } itemnextp = newp; } @@ -493,7 +493,7 @@ private: } // VISITORS - virtual void visit(AstCase* nodep) override { + void visit(AstCase* nodep) override { V3Case::caseLint(nodep); iterateChildren(nodep); if (debug() >= 9) nodep->dumpTree(cout, " case_old: "); @@ -510,7 +510,7 @@ private: } } //-------------------- - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { if (VN_IS(nodep, Always)) m_alwaysp = nodep; iterateChildren(nodep); } @@ -521,7 +521,7 @@ public: for (auto& itr : m_valueItem) itr = nullptr; iterate(nodep); } - virtual ~CaseVisitor() override { + ~CaseVisitor() override { V3Stats::addStat("Optimizations, Cases parallelized", m_statCaseFast); V3Stats::addStat("Optimizations, Cases complex", m_statCaseSlow); } @@ -533,7 +533,7 @@ public: void V3Case::caseAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { CaseVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("case", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("case", 0, dumpTree() >= 3); } void V3Case::caseLint(AstNodeCase* nodep) { UINFO(4, __FUNCTION__ << ": " << endl); diff --git a/src/V3Cast.cpp b/src/V3Cast.cpp index fa5b748e9..0ab4f4202 100644 --- a/src/V3Cast.cpp +++ b/src/V3Cast.cpp @@ -47,6 +47,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Cast state, as a visitor of each AstNode @@ -60,7 +62,6 @@ private: // STATE // METHODS - VL_DEBUG_FUNC; // Declare debug() void insertCast(AstNode* nodep, int needsize) { // We'll insert ABOVE passed node UINFO(4, " NeedCast " << nodep << endl); @@ -111,25 +112,25 @@ private: } // VISITORS - virtual void visit(AstNodeUniop* nodep) override { + void visit(AstNodeUniop* nodep) override { iterateChildren(nodep); nodep->user1(nodep->lhsp()->user1()); if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp()); } - virtual void visit(AstNodeBiop* nodep) override { + void visit(AstNodeBiop* nodep) override { iterateChildren(nodep); nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1()); if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp()); if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp()); } - virtual void visit(AstNodeTriop* nodep) override { + void visit(AstNodeTriop* nodep) override { iterateChildren(nodep); nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1() | nodep->thsp()->user1()); if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp()); if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp()); if (nodep->sizeMattersThs()) ensureCast(nodep->thsp()); } - virtual void visit(AstNodeQuadop* nodep) override { + void visit(AstNodeQuadop* nodep) override { iterateChildren(nodep); nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1() | nodep->thsp()->user1() | nodep->fhsp()->user1()); @@ -138,12 +139,12 @@ private: if (nodep->sizeMattersThs()) ensureCast(nodep->thsp()); if (nodep->sizeMattersFhs()) ensureCast(nodep->fhsp()); } - virtual void visit(AstCCast* nodep) override { + void visit(AstCCast* nodep) override { iterateChildren(nodep); ensureLower32Cast(nodep); nodep->user1(1); } - virtual void visit(AstNegate* nodep) override { + void visit(AstNegate* nodep) override { iterateChildren(nodep); nodep->user1(nodep->lhsp()->user1()); if (nodep->lhsp()->widthMin() == 1) { @@ -155,7 +156,7 @@ private: ensureCast(nodep->lhsp()); } } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { const AstNode* const backp = nodep->backp(); if (nodep->access().isReadOnly() && !VN_IS(backp, CCast) && VN_IS(backp, NodeMath) && !VN_IS(backp, ArraySel) && !VN_IS(backp, RedXor) && backp->width() @@ -166,7 +167,7 @@ private: } nodep->user1(1); } - virtual void visit(AstConst* nodep) override { + void visit(AstConst* nodep) override { // Constants are of unknown size if smaller than 33 bits, because // we're too lazy to wrap every constant in the universe in // ((IData)#). @@ -174,29 +175,29 @@ private: } // Null dereference protection - virtual void visit(AstNullCheck* nodep) override { + void visit(AstNullCheck* nodep) override { iterateChildren(nodep); nodep->user1(nodep->lhsp()->user1()); } - virtual void visit(AstCMethodCall* nodep) override { + void visit(AstCMethodCall* nodep) override { iterateChildren(nodep); ensureNullChecked(nodep->fromp()); } - virtual void visit(AstMemberSel* nodep) override { + void visit(AstMemberSel* nodep) override { iterateChildren(nodep); ensureNullChecked(nodep->fromp()); } // NOPs - virtual void visit(AstVar*) override {} + void visit(AstVar*) override {} //-------------------- - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit CastVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~CastVisitor() override = default; + ~CastVisitor() override = default; }; //###################################################################### @@ -205,5 +206,5 @@ public: void V3Cast::castAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { CastVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("cast", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("cast", 0, dumpTree() >= 3); } diff --git a/src/V3Cdc.cpp b/src/V3Cdc.cpp index 56e26ebe8..dc1e5a3e3 100644 --- a/src/V3Cdc.cpp +++ b/src/V3Cdc.cpp @@ -38,13 +38,14 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + constexpr int CDC_WEIGHT_ASYNC = 0x1000; // Weight for edges that feed async logic //###################################################################### class CdcBaseVisitor VL_NOT_FINAL : public VNVisitor { public: - VL_DEBUG_FUNC; // Declare debug() }; //###################################################################### @@ -67,9 +68,9 @@ public: , m_srcDomainSet{false} , m_dstDomainSet{false} , m_asyncPath{false} {} - virtual ~CdcEitherVertex() override = default; + ~CdcEitherVertex() override = default; // ACCESSORS - virtual FileLine* fileline() const override { return nodep()->fileline(); } + FileLine* fileline() const override { return nodep()->fileline(); } AstScope* scopep() const { return m_scopep; } AstNode* nodep() const { return m_nodep; } AstSenTree* srcDomainp() const { return m_srcDomainp; } @@ -93,11 +94,11 @@ public: CdcVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) : CdcEitherVertex{graphp, scopep, varScp} , m_varScp{varScp} {} - virtual ~CdcVarVertex() override = default; + ~CdcVarVertex() override = default; // ACCESSORS AstVarScope* varScp() const { return m_varScp; } - virtual string name() const override { return (cvtToHex(m_varScp) + " " + varScp()->name()); } - virtual string dotColor() const override { + string name() const override { return (cvtToHex(m_varScp) + " " + varScp()->name()); } + string dotColor() const override { return fromFlop() ? "green" : cntAsyncRst() ? "red" : "blue"; } int cntAsyncRst() const { return m_cntAsyncRst; } @@ -118,12 +119,10 @@ public: srcDomainp(sensenodep); dstDomainp(sensenodep); } - virtual ~CdcLogicVertex() override = default; + ~CdcLogicVertex() override = default; // ACCESSORS - virtual string name() const override { - return (cvtToHex(nodep()) + "@" + scopep()->prettyName()); - } - virtual string dotColor() const override { return hazard() ? "black" : "yellow"; } + string name() const override { return (cvtToHex(nodep()) + "@" + scopep()->prettyName()); } + string dotColor() const override { return hazard() ? "black" : "yellow"; } bool hazard() const { return m_hazard; } void setHazard(AstNode* nodep) { m_hazard = true; @@ -144,7 +143,7 @@ private: std::ofstream* const m_ofp = nullptr; // Output file string m_prefix; - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { *m_ofp << m_prefix; if (nodep->user3()) { *m_ofp << " %%"; @@ -171,7 +170,7 @@ public: , m_prefix{prefix} { iterate(nodep); } - virtual ~CdcDumpVisitor() override = default; + ~CdcDumpVisitor() override = default; }; //###################################################################### @@ -181,7 +180,7 @@ private: int m_maxLineno = 0; size_t m_maxFilenameLen = 0; - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { iterateChildren(nodep); // Keeping line+filename lengths separate is much faster than calling ascii().length() if (nodep->fileline()->lineno() >= m_maxLineno) { @@ -195,7 +194,7 @@ private: public: // CONSTRUCTORS explicit CdcWidthVisitor(AstNode* nodep) { iterate(nodep); } - virtual ~CdcWidthVisitor() override = default; + ~CdcWidthVisitor() override = default; // ACCESSORS int maxWidth() const { size_t width = 1; @@ -325,13 +324,11 @@ private: void analyze() { UINFO(3, __FUNCTION__ << ": " << endl); - // if (debug() > 6) m_graph.dump(); - if (debug() > 6) m_graph.dumpDotFilePrefixed("cdc_pre"); + if (dumpGraph() > 6) m_graph.dumpDotFilePrefixed("cdc_pre"); + // This will MAX across edge weights + m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue); // - m_graph.removeRedundantEdges( - &V3GraphEdge::followAlwaysTrue); // This will MAX across edge weights - // - m_graph.dumpDotFilePrefixed("cdc_simp"); + if (dumpGraph() >= 3) m_graph.dumpDotFilePrefixed("cdc_simp"); // analyzeReset(); } @@ -628,21 +625,21 @@ private: } // VISITORS - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { VL_RESTORER(m_modp); { m_modp = nodep; iterateChildren(nodep); } } - virtual void visit(AstScope* nodep) override { + void visit(AstScope* nodep) override { UINFO(4, " SCOPE " << nodep << endl); m_scopep = nodep; m_logicVertexp = nullptr; iterateChildren(nodep); m_scopep = nullptr; } - virtual void visit(AstActive* nodep) override { + void visit(AstActive* nodep) override { // Create required blocks and add to module UINFO(4, " BLOCK " << nodep << endl); AstNode::user2ClearTree(); @@ -654,7 +651,7 @@ private: m_domainp = nullptr; AstNode::user2ClearTree(); } - virtual void visit(AstNodeVarRef* nodep) override { + void visit(AstNodeVarRef* nodep) override { if (m_scopep) { UASSERT_OBJ(m_logicVertexp, nodep, "Var ref not under a logic block"); AstVarScope* const varscp = nodep->varScopep(); @@ -682,53 +679,53 @@ private: } } } - virtual void visit(AstAssignDly* nodep) override { + void visit(AstAssignDly* nodep) override { m_inDly = true; iterateChildren(nodep); m_inDly = false; } - virtual void visit(AstSenItem* nodep) override { + void visit(AstSenItem* nodep) override { m_inSenItem = true; iterateChildren(nodep); m_inSenItem = false; } - virtual void visit(AstAlways* nodep) override { iterateNewStmt(nodep); } - virtual void visit(AstAlwaysPublic* nodep) override { + void visit(AstAlways* nodep) override { iterateNewStmt(nodep); } + void visit(AstAlwaysPublic* nodep) override { // CDC doesn't care about public variables } - virtual void visit(AstCFunc* nodep) override { iterateNewStmt(nodep); } - virtual void visit(AstAssignAlias* nodep) override { iterateNewStmt(nodep); } - virtual void visit(AstAssignW* nodep) override { iterateNewStmt(nodep); } + void visit(AstCFunc* nodep) override { iterateNewStmt(nodep); } + void visit(AstAssignAlias* nodep) override { iterateNewStmt(nodep); } + void visit(AstAssignW* nodep) override { iterateNewStmt(nodep); } // Math that shouldn't cause us to clear hazard - virtual void visit(AstConst*) override {} - virtual void visit(AstReplicate* nodep) override { iterateChildren(nodep); } - virtual void visit(AstConcat* nodep) override { iterateChildren(nodep); } - virtual void visit(AstNot* nodep) override { iterateChildren(nodep); } - virtual void visit(AstSel* nodep) override { + void visit(AstConst*) override {} + void visit(AstReplicate* nodep) override { iterateChildren(nodep); } + void visit(AstConcat* nodep) override { iterateChildren(nodep); } + void visit(AstNot* nodep) override { iterateChildren(nodep); } + void visit(AstSel* nodep) override { if (!VN_IS(nodep->lsbp(), Const)) setNodeHazard(nodep); iterateChildren(nodep); } - virtual void visit(AstNodeSel* nodep) override { + void visit(AstNodeSel* nodep) override { if (!VN_IS(nodep->bitp(), Const)) setNodeHazard(nodep); iterateChildren(nodep); } // Ignores - virtual void visit(AstInitial*) override {} - virtual void visit(AstInitialAutomatic*) override {} - virtual void visit(AstInitialStatic*) override {} - virtual void visit(AstTraceDecl*) override {} - virtual void visit(AstCoverToggle*) override {} - virtual void visit(AstNodeDType*) override {} + void visit(AstInitial*) override {} + void visit(AstInitialAutomatic*) override {} + void visit(AstInitialStatic*) override {} + void visit(AstTraceDecl*) override {} + void visit(AstCoverToggle*) override {} + void visit(AstNodeDType*) override {} //-------------------- // Default - virtual void visit(AstNodeMath* nodep) override { + void visit(AstNodeMath* nodep) override { setNodeHazard(nodep); iterateChildren(nodep); } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -754,7 +751,7 @@ public: *m_ofp << '\n'; } } - virtual ~CdcVisitor() override { + ~CdcVisitor() override { if (m_ofp) VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); } }; diff --git a/src/V3Changed.cpp b/src/V3Changed.cpp index 32bf3d4c5..41652250f 100644 --- a/src/V3Changed.cpp +++ b/src/V3Changed.cpp @@ -36,6 +36,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### class ChangedState final { @@ -67,7 +69,7 @@ public: m_tlChgFuncp->isStatic(false); m_tlChgFuncp->isLoose(true); m_tlChgFuncp->declPrivate(true); - m_scopetopp->addActivep(m_tlChgFuncp); + m_scopetopp->addBlocksp(m_tlChgFuncp); // Each change detection function needs at least one AstChangeDet // to ensure that V3EmitC outputs the necessary code. maybeCreateMidChg(); @@ -86,7 +88,7 @@ public: m_chgFuncp->isStatic(false); m_chgFuncp->isLoose(true); m_chgFuncp->declPrivate(true); - m_scopetopp->addActivep(m_chgFuncp); + m_scopetopp->addBlocksp(m_chgFuncp); // Add a top call to it AstCCall* const callp = new AstCCall{m_scopetopp->fileline(), m_chgFuncp}; @@ -155,13 +157,13 @@ private: m_state.m_numStmts += initp->nodeCount() + m_varEqnp->widthWords(); } - virtual void visit(AstBasicDType*) override { // + void visit(AstBasicDType*) override { // newChangeDet(); } - virtual void visit(AstPackArrayDType*) override { // + void visit(AstPackArrayDType*) override { // newChangeDet(); } - virtual void visit(AstUnpackArrayDType* nodep) override { + void visit(AstUnpackArrayDType* nodep) override { for (int index = 0; index < nodep->elementsConst(); ++index) { VL_RESTORER(m_varEqnp); VL_RESTORER(m_newLvEqnp); @@ -181,7 +183,7 @@ private: } } } - virtual void visit(AstNodeUOrStructDType* nodep) override { + void visit(AstNodeUOrStructDType* nodep) override { if (nodep->packedUnsup()) { newChangeDet(); } else { @@ -191,7 +193,7 @@ private: << m_vscp->varp()->prettyNameQ()); } } - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { iterateChildren(nodep); if (debug()) nodep->dumpTree(cout, "-DETECTARRAY-general-"); m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable" @@ -218,9 +220,9 @@ public: // CHANGEDET(VARREF(_last), VARREF(var)) AstVar* const newvarp = new AstVar{varp->fileline(), VVarType::MODULETEMP, newvarname, varp}; - m_state.m_topModp->addStmtp(newvarp); + m_state.m_topModp->addStmtsp(newvarp); m_newvscp = new AstVarScope{m_vscp->fileline(), m_state.m_scopetopp, newvarp}; - m_state.m_scopetopp->addVarp(m_newvscp); + m_state.m_scopetopp->addVarsp(m_newvscp); m_varEqnp = new AstVarRef{m_vscp->fileline(), m_vscp, VAccess::READ}; m_newLvEqnp = new AstVarRef{m_vscp->fileline(), m_newvscp, VAccess::WRITE}; @@ -231,7 +233,7 @@ public: m_newLvEqnp->deleteTree(); m_newRvEqnp->deleteTree(); } - virtual ~ChangedInsertVisitor() override = default; + ~ChangedInsertVisitor() override = default; VL_UNCOPYABLE(ChangedInsertVisitor); }; @@ -252,5 +254,5 @@ void V3Changed::changedAll(AstNetlist* nodep) { } }); - V3Global::dumpCheckGlobalTree("changed", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("changed", 0, dumpTree() >= 3); } diff --git a/src/V3Class.cpp b/src/V3Class.cpp index 94f513802..810fe95d7 100644 --- a/src/V3Class.cpp +++ b/src/V3Class.cpp @@ -28,6 +28,8 @@ #include "V3Ast.h" #include "V3Global.h" +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### class ClassVisitor final : public VNVisitor { @@ -47,14 +49,13 @@ private: std::vector> m_toPackageMoves; // METHODS - VL_DEBUG_FUNC; // Declare debug() - virtual void visit(AstClass* nodep) override { + void visit(AstClass* nodep) override { if (nodep->user1SetOnce()) return; // Move this class nodep->name(m_prefix + nodep->name()); nodep->unlinkFrBack(); - v3Global.rootp()->addModulep(nodep); + v3Global.rootp()->addModulesp(nodep); // Make containing package // Note origName is the same as the class origName so errors look correct AstClassPackage* const packagep @@ -62,7 +63,7 @@ private: packagep->name(nodep->name() + "__Vclpkg"); nodep->classOrPackagep(packagep); packagep->classp(nodep); - v3Global.rootp()->addModulep(packagep); + v3Global.rootp()->addModulesp(packagep); // Add package to hierarchy AstCell* const cellp = new AstCell{packagep->fileline(), packagep->fileline(), @@ -72,7 +73,7 @@ private: nullptr, nullptr}; cellp->modp(packagep); - v3Global.rootp()->topModulep()->addStmtp(cellp); + v3Global.rootp()->topModulep()->addStmtsp(cellp); // Find class's scope // Alternative would be to move this and related to V3Scope const AstScope* classScopep = nullptr; @@ -85,7 +86,7 @@ private: AstScope* const scopep = new AstScope{nodep->fileline(), packagep, classScopep->name(), classScopep->aboveScopep(), classScopep->aboveCellp()}; - packagep->addStmtp(scopep); + packagep->addStmtsp(scopep); // Iterate VL_RESTORER(m_prefix); VL_RESTORER(m_classPackagep); @@ -100,7 +101,7 @@ private: } nodep->repairCache(); } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { // Visit for NodeModules that are not AstClass (AstClass is-a AstNodeModule) VL_RESTORER(m_prefix); { @@ -109,7 +110,7 @@ private: } } - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { iterateChildren(nodep); if (m_packageScopep) { if (m_ftaskp && m_ftaskp->lifetime().isStatic()) { @@ -127,12 +128,12 @@ private: } } - virtual void visit(AstVarScope* nodep) override { + void visit(AstVarScope* nodep) override { iterateChildren(nodep); nodep->varp()->user1p(nodep); } - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstNodeFTask* nodep) override { VL_RESTORER(m_ftaskp); { m_ftaskp = nodep; @@ -142,7 +143,7 @@ private: } } } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { iterateChildren(nodep); // Don't move now, or wouldn't keep interating the class // TODO move function statics only @@ -150,14 +151,14 @@ private: // m_toScopeMoves.push_back(std::make_pair(nodep, m_classScopep)); //} } - virtual void visit(AstInitial* nodep) override { + void visit(AstInitial* nodep) override { // But not AstInitialAutomatic, which remains under the class iterateChildren(nodep); if (m_packageScopep) { m_toScopeMoves.emplace_back(std::make_pair(nodep, m_packageScopep)); } } - virtual void visit(AstInitialStatic* nodep) override { + void visit(AstInitialStatic* nodep) override { // But not AstInitialAutomatic, which remains under the class iterateChildren(nodep); if (m_packageScopep) { @@ -165,28 +166,28 @@ private: } } - virtual void visit(AstNodeMath* nodep) override {} // Short circuit - virtual void visit(AstNodeStmt* nodep) override {} // Short circuit - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNodeMath* nodep) override {} // Short circuit + void visit(AstNodeStmt* nodep) override {} // Short circuit + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit ClassVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~ClassVisitor() override { + ~ClassVisitor() override { for (auto moved : m_toScopeMoves) { AstNode* const nodep = moved.first; AstScope* const scopep = moved.second; UINFO(9, "moving " << nodep << " to " << scopep << endl); if (VN_IS(nodep, NodeFTask)) { - scopep->addActivep(nodep->unlinkFrBack()); + scopep->addBlocksp(nodep->unlinkFrBack()); } else if (VN_IS(nodep, Var)) { AstVarScope* const vscp = VN_AS(nodep->user1p(), VarScope); vscp->scopep(scopep); vscp->unlinkFrBack(); - scopep->addVarp(vscp); + scopep->addVarsp(vscp); } else if (VN_IS(nodep, Initial) || VN_IS(nodep, InitialStatic)) { nodep->unlinkFrBack(); - scopep->addActivep(nodep); + scopep->addBlocksp(nodep); } else { nodep->v3fatalSrc("Bad case"); } @@ -196,7 +197,7 @@ public: AstNodeModule* const modp = moved.second; UINFO(9, "moving " << nodep << " to " << modp << endl); nodep->unlinkFrBack(); - modp->addStmtp(nodep); + modp->addStmtsp(nodep); } } }; @@ -207,5 +208,5 @@ public: void V3Class::classAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { ClassVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("class", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("class", 0, dumpTree() >= 3); } diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp index 3cca98d7f..cd9c96d7d 100644 --- a/src/V3Clean.cpp +++ b/src/V3Clean.cpp @@ -33,6 +33,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Clean state, as a visitor of each AstNode @@ -54,7 +56,6 @@ private: const AstNodeModule* m_modp = nullptr; // METHODS - VL_DEBUG_FUNC; // Declare debug() // Width resetting int cppWidth(AstNode* nodep) { @@ -173,134 +174,134 @@ private: } // VISITORS - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { VL_RESTORER(m_modp); { m_modp = nodep; iterateChildren(nodep); } } - virtual void visit(AstNodeUniop* nodep) override { + void visit(AstNodeUniop* nodep) override { iterateChildren(nodep); computeCppWidth(nodep); if (nodep->cleanLhs()) ensureClean(nodep->lhsp()); setClean(nodep, nodep->cleanOut()); } - virtual void visit(AstNodeBiop* nodep) override { + void visit(AstNodeBiop* nodep) override { operandBiop(nodep); setClean(nodep, nodep->cleanOut()); } - virtual void visit(AstAnd* nodep) override { + void visit(AstAnd* nodep) override { operandBiop(nodep); setClean(nodep, isClean(nodep->lhsp()) || isClean(nodep->rhsp())); } - virtual void visit(AstXor* nodep) override { + void visit(AstXor* nodep) override { operandBiop(nodep); setClean(nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp())); } - virtual void visit(AstOr* nodep) override { + void visit(AstOr* nodep) override { operandBiop(nodep); setClean(nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp())); } - virtual void visit(AstNodeQuadop* nodep) override { + void visit(AstNodeQuadop* nodep) override { operandQuadop(nodep); setClean(nodep, nodep->cleanOut()); } - virtual void visit(AstNodeMath* nodep) override { + void visit(AstNodeMath* nodep) override { iterateChildren(nodep); computeCppWidth(nodep); setClean(nodep, nodep->cleanOut()); } - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { iterateChildren(nodep); computeCppWidth(nodep); if (nodep->cleanRhs()) ensureClean(nodep->rhsp()); } - virtual void visit(AstText* nodep) override { // + void visit(AstText* nodep) override { // setClean(nodep, true); } - virtual void visit(AstScopeName* nodep) override { // + void visit(AstScopeName* nodep) override { // setClean(nodep, true); } - virtual void visit(AstCNew* nodep) override { + void visit(AstCNew* nodep) override { iterateChildren(nodep); setClean(nodep, true); } - virtual void visit(AstSel* nodep) override { + void visit(AstSel* nodep) override { operandTriop(nodep); setClean(nodep, nodep->cleanOut()); } - virtual void visit(AstUCFunc* nodep) override { + void visit(AstUCFunc* nodep) override { iterateChildren(nodep); computeCppWidth(nodep); setClean(nodep, false); // We always clean, as we don't trust those pesky users. if (!VN_IS(nodep->backp(), And)) insertClean(nodep); - ensureCleanAndNext(nodep->bodysp()); + ensureCleanAndNext(nodep->exprsp()); } - virtual void visit(AstTraceDecl* nodep) override { + void visit(AstTraceDecl* nodep) override { // No cleaning, or would loose pointer to enum iterateChildren(nodep); } - virtual void visit(AstTraceInc* nodep) override { + void visit(AstTraceInc* nodep) override { iterateChildren(nodep); ensureCleanAndNext(nodep->valuep()); } - virtual void visit(AstTypedef* nodep) override { + void visit(AstTypedef* nodep) override { // No cleaning, or would loose pointer to enum iterateChildren(nodep); } - virtual void visit(AstParamTypeDType* nodep) override { + void visit(AstParamTypeDType* nodep) override { // No cleaning, or would loose pointer to enum iterateChildren(nodep); } // Control flow operators - virtual void visit(AstNodeCond* nodep) override { + void visit(AstNodeCond* nodep) override { iterateChildren(nodep); ensureClean(nodep->condp()); - setClean(nodep, isClean(nodep->expr1p()) && isClean(nodep->expr2p())); + setClean(nodep, isClean(nodep->thenp()) && isClean(nodep->elsep())); } - virtual void visit(AstWhile* nodep) override { + void visit(AstWhile* nodep) override { iterateChildren(nodep); ensureClean(nodep->condp()); } - virtual void visit(AstNodeIf* nodep) override { + void visit(AstNodeIf* nodep) override { iterateChildren(nodep); ensureClean(nodep->condp()); } - virtual void visit(AstSFormatF* nodep) override { + void visit(AstSFormatF* nodep) override { iterateChildren(nodep); ensureCleanAndNext(nodep->exprsp()); setClean(nodep, true); // generates a string, so not relevant } - virtual void visit(AstUCStmt* nodep) override { + void visit(AstUCStmt* nodep) override { iterateChildren(nodep); - ensureCleanAndNext(nodep->bodysp()); + ensureCleanAndNext(nodep->exprsp()); } - virtual void visit(AstNodeCCall* nodep) override { + void visit(AstNodeCCall* nodep) override { iterateChildren(nodep); ensureCleanAndNext(nodep->argsp()); setClean(nodep, true); } - virtual void visit(AstCMethodHard* nodep) override { + void visit(AstCMethodHard* nodep) override { iterateChildren(nodep); ensureCleanAndNext(nodep->pinsp()); setClean(nodep, true); } - virtual void visit(AstWith* nodep) override { + void visit(AstWith* nodep) override { iterateChildren(nodep); ensureCleanAndNext(nodep->exprp()); setClean(nodep, true); } - virtual void visit(AstIntfRef* nodep) override { + void visit(AstIntfRef* nodep) override { iterateChildren(nodep); setClean(nodep, true); // generates a string, so not relevant } //-------------------- // Default: Just iterate - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { iterateChildren(nodep); computeCppWidth(nodep); } @@ -308,7 +309,7 @@ private: public: // CONSTRUCTORS explicit CleanVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~CleanVisitor() override = default; + ~CleanVisitor() override = default; }; //###################################################################### @@ -317,5 +318,5 @@ public: void V3Clean::cleanAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { CleanVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("clean", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("clean", 0, dumpTree() >= 3); } diff --git a/src/V3Clock.cpp b/src/V3Clock.cpp index d94728f35..af7f6dd79 100644 --- a/src/V3Clock.cpp +++ b/src/V3Clock.cpp @@ -37,6 +37,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Convert every WRITE AstVarRef to a READ ref @@ -88,7 +90,6 @@ private: AstMTaskBody* m_mtaskBodyp = nullptr; // Current mtask body // METHODS - VL_DEBUG_FUNC; // Declare debug() AstVarScope* getCreateLastClk(AstVarScope* vscp) { if (vscp->user1p()) return static_cast(vscp->user1p()); @@ -100,12 +101,12 @@ private: const string newvarname = (string("__Vclklast__") + vscp->scopep()->nameDotless() + "__" + varp->name()); AstVar* const newvarp = new AstVar(vscp->fileline(), VVarType::MODULETEMP, newvarname, - VFlagLogicPacked(), 1); + VFlagLogicPacked{}, 1); newvarp->noReset(true); // Reset by below assign - m_modp->addStmtp(newvarp); + m_modp->addStmtsp(newvarp); AstVarScope* const newvscp = new AstVarScope(vscp->fileline(), m_scopep, newvarp); vscp->user1p(newvscp); - m_scopep->addVarp(newvscp); + m_scopep->addVarsp(newvscp); // Add init AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, VAccess::READ); if (v3Global.opt.xInitialEdge()) fromp = new AstNot(fromp->fileline(), fromp); @@ -202,7 +203,7 @@ private: funcp->slow(slow); funcp->isConst(false); funcp->declPrivate(true); - m_topScopep->scopep()->addActivep(funcp); + m_topScopep->scopep()->addBlocksp(funcp); return funcp; } void splitCheck(AstCFunc* ofuncp) { @@ -229,7 +230,7 @@ private: funcp->isStatic(false); funcp->isLoose(true); funcp->slow(ofuncp->slow()); - m_topScopep->scopep()->addActivep(funcp); + m_topScopep->scopep()->addBlocksp(funcp); // AstCCall* const callp = new AstCCall{funcp->fileline(), funcp}; ofuncp->addStmtsp(callp); @@ -242,7 +243,7 @@ private: } // VISITORS - virtual void visit(AstTopScope* nodep) override { + void visit(AstTopScope* nodep) override { UINFO(4, " TOPSCOPE " << nodep << endl); m_topScopep = nodep; m_scopep = nodep->scopep(); @@ -277,7 +278,7 @@ private: m_topScopep = nullptr; m_scopep = nullptr; } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { // UINFO(4, " MOD " << nodep << endl); VL_RESTORER(m_modp); { @@ -285,7 +286,7 @@ private: iterateChildren(nodep); } } - virtual void visit(AstScope* nodep) override { + void visit(AstScope* nodep) override { // UINFO(4, " SCOPE " << nodep << endl); m_scopep = nodep; iterateChildren(nodep); @@ -296,14 +297,14 @@ private: } m_scopep = nullptr; } - virtual void visit(AstNodeProcedure* nodep) override { - if (AstNode* const stmtsp = nodep->bodysp()) { + void visit(AstNodeProcedure* nodep) override { + if (AstNode* const stmtsp = nodep->stmtsp()) { stmtsp->unlinkFrBackWithNext(); nodep->addNextHere(stmtsp); } VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } - virtual void visit(AstCoverToggle* nodep) override { + void visit(AstCoverToggle* nodep) override { // nodep->dumpTree(cout, "ct:"); // COVERTOGGLE(INC, ORIG, CHANGE) -> // IF(ORIG ^ CHANGE) { INC; CHANGE = ORIG; } @@ -316,11 +317,11 @@ private: // We could add another IF to detect posedges, and only increment if so. // It's another whole branch though versus a potential memory miss. // We'll go with the miss. - newp->addIfsp(new AstAssign(nodep->fileline(), changeWrp, origp->cloneTree(false))); + newp->addThensp(new AstAssign(nodep->fileline(), changeWrp, origp->cloneTree(false))); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { iterateChildren(nodep); // Link to global function if (nodep->isFinal()) { @@ -329,7 +330,7 @@ private: m_finalFuncp->addStmtsp(callp); } } - virtual void visit(AstSenTree* nodep) override { + void visit(AstSenTree* nodep) override { // Delete it later; Actives still pointing to it nodep->unlinkFrBack(); pushDeletep(nodep); @@ -343,7 +344,7 @@ private: void addToInitial(AstNode* stmtsp) { m_initFuncp->addStmtsp(stmtsp); // add to top level function } - virtual void visit(AstActive* nodep) override { + void visit(AstActive* nodep) override { // Careful if adding variables here, ACTIVES can be under other ACTIVES // Need to save and restore any member state in AstUntilStable block if (!m_topScopep || !nodep->stmtsp()) { @@ -367,7 +368,7 @@ private: m_mtaskBodyp->addStmtsp(m_lastIfp); } // Move statements to if - m_lastIfp->addIfsp(stmtsp); + m_lastIfp->addThensp(stmtsp); } else if (nodep->hasInitial() || nodep->hasSettle()) { nodep->v3fatalSrc("MTask should not include initial/settle logic."); } else { @@ -393,7 +394,7 @@ private: addToEvalLoop(m_lastIfp); } // Move statements to if - m_lastIfp->addIfsp(stmtsp); + m_lastIfp->addThensp(stmtsp); } else if (nodep->hasInitial()) { // Don't need to: clearLastSen();, as we're adding it to different cfunc // Move statements to function @@ -411,7 +412,7 @@ private: VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } } - virtual void visit(AstExecGraph* nodep) override { + void visit(AstExecGraph* nodep) override { VL_RESTORER(m_mtaskBodyp); for (m_mtaskBodyp = nodep->mTaskBodiesp(); m_mtaskBodyp; m_mtaskBodyp = VN_AS(m_mtaskBodyp->nextp(), MTaskBody)) { @@ -427,7 +428,7 @@ private: } //-------------------- - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -437,7 +438,7 @@ public: // easily without iterating through the tree. nodep->evalp(m_evalFuncp); } - virtual ~ClockVisitor() override = default; + ~ClockVisitor() override = default; }; //###################################################################### @@ -446,5 +447,5 @@ public: void V3Clock::clockAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { ClockVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("clock", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("clock", 0, dumpTree() >= 3); } diff --git a/src/V3Combine.cpp b/src/V3Combine.cpp index 8fa0edbeb..7d61aae35 100644 --- a/src/V3Combine.cpp +++ b/src/V3Combine.cpp @@ -33,6 +33,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + class CombineVisitor final : VNVisitor { // NODE STATE // AstNodeModule::user1() List of AstCFuncs in this module (via m_cfuncs) @@ -57,7 +59,6 @@ class CombineVisitor final : VNVisitor { VDouble0 m_cfuncsCombined; // Statistic tracking // METHODS - VL_DEBUG_FUNC; // Declare debug() void removeEmptyFunctions(std::list& funcps) { for (funcit_t it = funcps.begin(), nit; it != funcps.end(); it = nit) { @@ -180,32 +181,32 @@ class CombineVisitor final : VNVisitor { } // VISITORS - virtual void visit(AstNetlist* nodep) override { + void visit(AstNetlist* nodep) override { // Gather functions and references iterateChildrenConst(nodep); // Combine functions process(nodep); } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { UASSERT_OBJ(!m_modp, nodep, "Should not nest"); m_modp = nodep; iterateChildrenConst(nodep); m_modp = nullptr; } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { iterateChildrenConst(nodep); if (nodep->dontCombine()) return; auto& coll = nodep->slow() ? m_cfuncs(m_modp).m_slow : m_cfuncs(m_modp).m_fast; coll.emplace_back(nodep); } - virtual void visit(AstCCall* nodep) override { + void visit(AstCCall* nodep) override { iterateChildrenConst(nodep); AstCFunc* const funcp = nodep->funcp(); if (funcp->dontCombine()) return; m_callSites(funcp).emplace_back(nodep); } - virtual void visit(AstAddrOfCFunc* nodep) override { + void visit(AstAddrOfCFunc* nodep) override { iterateChildrenConst(nodep); if (nodep->funcp()->dontCombine()) return; // LCOV_EXCL_START @@ -217,7 +218,7 @@ class CombineVisitor final : VNVisitor { } //-------------------- - virtual void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } + void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } // CONSTRUCTORS explicit CombineVisitor(AstNetlist* nodep) { iterate(nodep); } @@ -235,5 +236,5 @@ public: void V3Combine::combineAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); CombineVisitor::apply(nodep); - V3Global::dumpCheckGlobalTree("combine", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("combine", 0, dumpTree() >= 3); } diff --git a/src/V3Common.cpp b/src/V3Common.cpp index 76521a3fd..9961585b9 100644 --- a/src/V3Common.cpp +++ b/src/V3Common.cpp @@ -29,6 +29,8 @@ #include "V3EmitCBase.h" #include "V3Global.h" +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Common component builders @@ -43,7 +45,7 @@ static void makeVlToString(AstClass* nodep) { AstNode* const exprp = new AstCMath{nodep->fileline(), "obj ? obj->to_string() : \"null\"", 0}; exprp->dtypeSetString(); funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp}); - nodep->addStmtp(funcp); + nodep->addStmtsp(funcp); } static void makeToString(AstClass* nodep) { AstCFunc* const funcp = new AstCFunc{nodep->fileline(), "to_string", nullptr, "std::string"}; @@ -54,7 +56,7 @@ static void makeToString(AstClass* nodep) { = new AstCMath{nodep->fileline(), R"(std::string{"'{"} + to_string_middle() + "}")", 0}; exprp->dtypeSetString(); funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp}); - nodep->addStmtp(funcp); + nodep->addStmtsp(funcp); } static void makeToStringMiddle(AstClass* nodep) { AstCFunc* const funcp @@ -96,7 +98,7 @@ static void makeToStringMiddle(AstClass* nodep) { funcp->addStmtsp(new AstCStmt{nodep->fileline(), stmt}); } funcp->addStmtsp(new AstCStmt{nodep->fileline(), "return out;\n"}); - nodep->addStmtp(funcp); + nodep->addStmtsp(funcp); } //###################################################################### @@ -117,5 +119,5 @@ void V3Common::commonAll() { makeToStringMiddle(classp); } } - V3Global::dumpCheckGlobalTree("common", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("common", 0, dumpTree() >= 3); } diff --git a/src/V3Config.cpp b/src/V3Config.cpp index 5961bf7d0..abfd4f295 100644 --- a/src/V3Config.cpp +++ b/src/V3Config.cpp @@ -27,6 +27,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Resolve wildcards in files, modules, ftasks or variables @@ -193,11 +195,11 @@ public: const VPragmaType type = m_inlineValue ? VPragmaType::INLINE_MODULE : VPragmaType::NO_INLINE_MODULE; AstNode* const nodep = new AstPragma(modp->fileline(), type); - modp->addStmtp(nodep); + modp->addStmtsp(nodep); } for (const auto& itr : m_modPragmas) { AstNode* const nodep = new AstPragma{modp->fileline(), itr}; - modp->addStmtp(nodep); + modp->addStmtsp(nodep); } } @@ -309,7 +311,7 @@ public: if (lineMatch(lineno, VPragmaType::FULL_CASE)) nodep->fullPragma(true); if (lineMatch(lineno, VPragmaType::PARALLEL_CASE)) nodep->parallelPragma(true); } - inline void applyIgnores(FileLine* filelinep) { + void applyIgnores(FileLine* filelinep) { // HOT routine, called each parsed token line of this filename if (m_lastIgnore.lineno != filelinep->lineno()) { // UINFO(9, " ApplyIgnores for " << filelinep->ascii() << endl); diff --git a/src/V3Const.cpp b/src/V3Const.cpp index fb90cf866..f091e04bc 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -37,6 +37,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Utilities @@ -350,7 +352,6 @@ class ConstBitOpTreeVisitor final : public VNVisitor { std::vector> m_varInfos; // VarInfo for each variable, [0] is nullptr // METHODS - VL_DEBUG_FUNC; // Declare debug() bool isAndTree() const { return VN_IS(m_rootp, And); } bool isOrTree() const { return VN_IS(m_rootp, Or); } @@ -417,14 +418,12 @@ class ConstBitOpTreeVisitor final : public VNVisitor { } // VISITORS - virtual void visit(AstNode* nodep) override { - CONST_BITOP_SET_FAILED("Hit unexpected op", nodep); - } - virtual void visit(AstCCast* nodep) override { + void visit(AstNode* nodep) override { CONST_BITOP_SET_FAILED("Hit unexpected op", nodep); } + void visit(AstCCast* nodep) override { iterateChildren(nodep); if (m_leafp) m_leafp->updateBitRange(nodep); } - virtual void visit(AstShiftR* nodep) override { + void visit(AstShiftR* nodep) override { CONST_BITOP_RETURN_IF(!m_leafp, nodep); AstConst* const constp = VN_CAST(nodep->rhsp(), Const); CONST_BITOP_RETURN_IF(!constp, nodep->rhsp()); @@ -434,7 +433,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor { m_leafp->updateBitRange(nodep); m_lsb -= constp->toUInt(); } - virtual void visit(AstNot* nodep) override { + void visit(AstNot* nodep) override { CONST_BITOP_RETURN_IF(nodep->widthMin() != 1, nodep); AstNode* lhsp = nodep->lhsp(); AstCCast* const castp = VN_CAST(lhsp, CCast); @@ -449,7 +448,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor { if (!isXorTree()) m_polarity = !m_polarity; if (m_leafp && castp) m_leafp->updateBitRange(castp); } - virtual void visit(AstWordSel* nodep) override { + void visit(AstWordSel* nodep) override { CONST_BITOP_RETURN_IF(!m_leafp, nodep); AstConst* const constp = VN_CAST(nodep->bitp(), Const); CONST_BITOP_RETURN_IF(!constp, nodep->rhsp()); @@ -457,17 +456,17 @@ class ConstBitOpTreeVisitor final : public VNVisitor { m_leafp->wordIdx(constp->toSInt()); iterate(nodep->fromp()); } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { CONST_BITOP_RETURN_IF(!m_leafp, nodep); m_leafp->setLeaf(nodep); m_leafp->polarity(m_polarity); } - virtual void visit(AstConst* nodep) override { + void visit(AstConst* nodep) override { CONST_BITOP_RETURN_IF(!m_leafp, nodep); m_leafp->setLeaf(nodep); } - virtual void visit(AstRedXor* nodep) override { + void visit(AstRedXor* nodep) override { Restorer restorer{*this}; CONST_BITOP_RETURN_IF(!VN_IS(m_rootp, Xor), nodep); AstNode* lhsp = nodep->lhsp(); @@ -514,7 +513,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor { } } - virtual void visit(AstNodeBiop* nodep) override { + void visit(AstNodeBiop* nodep) override { if (VN_IS(nodep, And) && isConst(nodep->lhsp(), 1)) { // 1 & _ // Always reach past a plain making AND Restorer restorer{*this}; @@ -895,7 +894,6 @@ private: V3UniqueNames m_concswapNames; // For generating unique temporary variable names // METHODS - VL_DEBUG_FUNC; // Declare debug() bool operandConst(AstNode* nodep) { return VN_IS(nodep, Const); } bool operandAsvConst(const AstNode* nodep) { @@ -1044,20 +1042,19 @@ private: // as high as possible, which is usally the right choice, except for this. AstNodeCond* const condp = VN_CAST(nodep->rhsp(), NodeCond); if (!condp) return false; - if (!VN_IS(condp->expr1p(), Const) && !VN_IS(condp->expr2p(), Const)) return false; + if (!VN_IS(condp->thenp(), Const) && !VN_IS(condp->elsep(), Const)) return false; AstConst* const maskp = VN_CAST(nodep->lhsp(), Const); if (!maskp) return false; UINFO(4, "AND(CONSTm, CONDcond(c, i, e))->CONDcond(c, AND(m,i), AND(m, e)) " << nodep << endl); - AstNodeCond* const newp = static_cast( - condp->cloneType(condp->condp()->unlinkFrBack(), - new AstAnd(nodep->fileline(), maskp->cloneTree(false), - condp->expr1p()->unlinkFrBack()), - new AstAnd(nodep->fileline(), maskp->cloneTree(false), - condp->expr2p()->unlinkFrBack()))); + AstNodeCond* const newp = static_cast(condp->cloneType( + condp->condp()->unlinkFrBack(), + new AstAnd(nodep->fileline(), maskp->cloneTree(false), condp->thenp()->unlinkFrBack()), + new AstAnd(nodep->fileline(), maskp->cloneTree(false), + condp->elsep()->unlinkFrBack()))); newp->dtypeFrom(nodep); - newp->expr1p()->dtypeFrom(nodep); // As And might have been to change widths - newp->expr2p()->dtypeFrom(nodep); + newp->thenp()->dtypeFrom(nodep); // As And might have been to change widths + newp->elsep()->dtypeFrom(nodep); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); return true; @@ -1445,19 +1442,19 @@ private: } } bool ifSameAssign(const AstNodeIf* nodep) { - const AstNodeAssign* const ifp = VN_CAST(nodep->ifsp(), NodeAssign); - const AstNodeAssign* const elsep = VN_CAST(nodep->elsesp(), NodeAssign); - if (!ifp || ifp->nextp()) return false; // Must be SINGLE statement - if (!elsep || elsep->nextp()) return false; - if (ifp->type() != elsep->type()) return false; // Can't mix an assigndly and an assign - if (!ifp->lhsp()->sameGateTree(elsep->lhsp())) return false; - if (!ifp->rhsp()->gateTree()) return false; - if (!elsep->rhsp()->gateTree()) return false; + const AstNodeAssign* const thensp = VN_CAST(nodep->thensp(), NodeAssign); + const AstNodeAssign* const elsesp = VN_CAST(nodep->elsesp(), NodeAssign); + if (!thensp || thensp->nextp()) return false; // Must be SINGLE statement + if (!elsesp || elsesp->nextp()) return false; + if (thensp->type() != elsesp->type()) return false; // Can't mix an assigndly with assign + if (!thensp->lhsp()->sameGateTree(elsesp->lhsp())) return false; + if (!thensp->rhsp()->gateTree()) return false; + if (!elsesp->rhsp()->gateTree()) return false; return true; } bool operandIfIf(const AstNodeIf* nodep) { if (nodep->elsesp()) return false; - const AstNodeIf* const lowerIfp = VN_CAST(nodep->ifsp(), NodeIf); + const AstNodeIf* const lowerIfp = VN_CAST(nodep->thensp(), NodeIf); if (!lowerIfp || lowerIfp->nextp()) return false; if (nodep->type() != lowerIfp->type()) return false; if (afterComment(lowerIfp->elsesp())) return false; @@ -2079,7 +2076,7 @@ private: AstSel* const sel2p = new AstSel(conp->fileline(), rhs2p, lsb2, msb2 - lsb2 + 1); // Make new assigns of same flavor as old one //*** Not cloneTree; just one node. - AstNode* newp = nullptr; + AstNodeAssign* newp = nullptr; if (!need_temp) { AstNodeAssign* const asn1ap = VN_AS(nodep->cloneType(lc1p, sel1p), NodeAssign); AstNodeAssign* const asn2ap = VN_AS(nodep->cloneType(lc2p, sel2p), NodeAssign); @@ -2099,8 +2096,8 @@ private: AstVar* const temp2p = new AstVar(sel2p->fileline(), VVarType::BLOCKTEMP, m_concswapNames.get(sel2p), VFlagLogicPacked(), msb2 - lsb2 + 1); - m_modp->addStmtp(temp1p); - m_modp->addStmtp(temp2p); + m_modp->addStmtsp(temp1p); + m_modp->addStmtsp(temp2p); AstNodeAssign* const asn1ap = VN_AS(nodep->cloneType( new AstVarRef(sel1p->fileline(), temp1p, VAccess::WRITE), sel1p), @@ -2252,11 +2249,11 @@ private: //---------------------------------------- // VISITORS - virtual void visit(AstNetlist* nodep) override { + void visit(AstNetlist* nodep) override { // Iterate modules backwards, in bottom-up order. That's faster iterateChildrenBackwards(nodep); } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { VL_RESTORER(m_modp); { m_modp = nodep; @@ -2264,7 +2261,7 @@ private: iterateChildren(nodep); } } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { // No ASSIGNW removals under funcs, we've long eliminated INITIALs // (We should perhaps rename the assignw's to just assigns) VL_RESTORER(m_wremove); @@ -2273,7 +2270,7 @@ private: iterateChildren(nodep); } } - virtual void visit(AstScope* nodep) override { + void visit(AstScope* nodep) override { // No ASSIGNW removals under scope, we've long eliminated INITIALs VL_RESTORER(m_wremove); VL_RESTORER(m_scopep); @@ -2370,17 +2367,17 @@ private: } // Special cases - virtual void visit(AstConst*) override {} // Already constant + void visit(AstConst*) override {} // Already constant - virtual void visit(AstCell* nodep) override { + void visit(AstCell* nodep) override { if (m_params) { iterateAndNextNull(nodep->paramsp()); } else { iterateChildren(nodep); } } - virtual void visit(AstClassOrPackageRef* nodep) override { iterateChildren(nodep); } - virtual void visit(AstPin* nodep) override { iterateChildren(nodep); } + void visit(AstClassOrPackageRef* nodep) override { iterateChildren(nodep); } + void visit(AstPin* nodep) override { iterateChildren(nodep); } void replaceLogEq(AstLogEq* nodep) { // LOGEQ(a,b) => AstLogAnd{AstLogOr{AstLogNot{a},b},AstLogOr{AstLogNot{b},a}} @@ -2562,7 +2559,7 @@ private: VL_DO_DANGLING(nodep->deleteTree(), nodep); } - virtual void visit(AstAttrOf* nodep) override { + void visit(AstAttrOf* nodep) override { VL_RESTORER(m_attrp); { m_attrp = nodep; @@ -2570,7 +2567,7 @@ private: } } - virtual void visit(AstArraySel* nodep) override { + void visit(AstArraySel* nodep) override { iterateAndNextNull(nodep->bitp()); if (VN_IS(nodep->bitp(), Const) && VN_IS(nodep->fromp(), VarRef) @@ -2596,7 +2593,7 @@ private: } m_selp = nullptr; } - virtual void visit(AstNodeVarRef* nodep) override { + void visit(AstNodeVarRef* nodep) override { iterateChildren(nodep); UASSERT_OBJ(nodep->varp(), nodep, "Not linked"); bool did = false; @@ -2650,7 +2647,7 @@ private: << nodep->varp()->prettyNameQ()); } } - virtual void visit(AstEnumItemRef* nodep) override { + void visit(AstEnumItemRef* nodep) override { iterateChildren(nodep); UASSERT_OBJ(nodep->itemp(), nodep, "Not linked"); bool did = false; @@ -2675,7 +2672,7 @@ private: } } - // virtual void visit(AstCvtPackString* nodep) override { + // void visit(AstCvtPackString* nodep) override { // Not constant propagated (for today) because AstNodeMath::isOpaque is set // Someday if lower is constant, convert to quoted "string". @@ -2683,7 +2680,7 @@ private: // Only one if it's not in a list return (!nodep->nextp() && nodep->backp()->nextp() != nodep); } - virtual void visit(AstSenItem* nodep) override { + void visit(AstSenItem* nodep) override { iterateChildren(nodep); if (m_doNConst && (VN_IS(nodep->sensp(), Const) || VN_IS(nodep->sensp(), EnumItemRef) @@ -2750,7 +2747,7 @@ private: } }; - virtual void visit(AstSenTree* nodep) override { + void visit(AstSenTree* nodep) override { iterateChildren(nodep); if (m_doExpensive) { // cout<dumpTree(cout, "ssin: "); @@ -2834,17 +2831,17 @@ private: //----- // Zero elimination - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { iterateChildren(nodep); if (m_doNConst && replaceNodeAssign(nodep)) return; } - virtual void visit(AstAssignAlias* nodep) override { + void visit(AstAssignAlias* nodep) override { // Don't perform any optimizations, keep the alias around } - virtual void visit(AstAssignVarScope* nodep) override { + void visit(AstAssignVarScope* nodep) override { // Don't perform any optimizations, the node won't be linked yet } - virtual void visit(AstAssignW* nodep) override { + void visit(AstAssignW* nodep) override { iterateChildren(nodep); if (m_doNConst && replaceNodeAssign(nodep)) return; AstNodeVarRef* const varrefp = VN_CAST( @@ -2853,6 +2850,7 @@ private: if (m_wremove && !m_params && m_doNConst && m_modp && operandConst(nodep->rhsp()) && !VN_AS(nodep->rhsp(), Const)->num().isFourState() && varrefp // Don't do messes with BITREFs/ARRAYREFs + && !varrefp->varp()->hasStrengthAssignment() // Strengths are resolved in V3Tristate && !varrefp->varp()->valuep() // Not already constified && !varrefp->varScopep()) { // Not scoped (or each scope may have different initial // value) @@ -2863,14 +2861,14 @@ private: varrefp->unlinkFrBack(); AstInitial* const newinitp = new AstInitial( nodep->fileline(), new AstAssign(nodep->fileline(), varrefp, exprp)); - m_modp->addStmtp(newinitp); + m_modp->addStmtsp(newinitp); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); // Set the initial value right in the variable so we can constant propagate AstNode* const initvaluep = exprp->cloneTree(false); varrefp->varp()->valuep(initvaluep); } } - virtual void visit(AstRelease* nodep) override { + void visit(AstRelease* nodep) override { if (AstConcat* const concatp = VN_CAST(nodep->lhsp(), Concat)) { FileLine* const flp = nodep->fileline(); AstRelease* const newLp = new AstRelease{flp, concatp->lhsp()->unlinkFrBack()}; @@ -2883,7 +2881,7 @@ private: } } - virtual void visit(AstNodeIf* nodep) override { + void visit(AstNodeIf* nodep) override { iterateChildren(nodep); if (m_doNConst) { if (const AstConst* const constp = VN_CAST(nodep->condp(), Const)) { @@ -2893,7 +2891,7 @@ private: keepp = nodep->elsesp(); } else if (!m_doV || constp->isNeqZero()) { // Might be X in Verilog UINFO(4, "IF(!0,{x},{any}) => {x}: " << nodep << endl); - keepp = nodep->ifsp(); + keepp = nodep->thensp(); } else { UINFO(4, "IF condition is X, retaining: " << nodep << endl); return; @@ -2905,7 +2903,7 @@ private: nodep->unlinkFrBack(); } VL_DO_DANGLING(nodep->deleteTree(), nodep); - } else if (!afterComment(nodep->ifsp()) && !afterComment(nodep->elsesp())) { + } else if (!afterComment(nodep->thensp()) && !afterComment(nodep->elsesp())) { if (!isTreePureRecurse(nodep->condp())) { // Condition has side effect - leave - perhaps in // future simplify to remove all but side effect terms @@ -2913,27 +2911,27 @@ private: // Empty block, remove it VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } - } else if (!afterComment(nodep->ifsp())) { + } else if (!afterComment(nodep->thensp())) { UINFO(4, "IF({x}) nullptr {...} => IF(NOT{x}}: " << nodep << endl); AstNode* const condp = nodep->condp(); AstNode* const elsesp = nodep->elsesp(); condp->unlinkFrBackWithNext(); elsesp->unlinkFrBackWithNext(); - if (nodep->ifsp()) { // Must have been comment - nodep->ifsp()->unlinkFrBackWithNext()->deleteTree(); + if (nodep->thensp()) { // Must have been comment + nodep->thensp()->unlinkFrBackWithNext()->deleteTree(); } nodep->condp(new AstLogNot(condp->fileline(), condp)); // LogNot, as C++ optimization also possible - nodep->addIfsp(elsesp); + nodep->addThensp(elsesp); } else if (((VN_IS(nodep->condp(), Not) && nodep->condp()->width() == 1) || VN_IS(nodep->condp(), LogNot)) - && nodep->ifsp() && nodep->elsesp()) { + && nodep->thensp() && nodep->elsesp()) { UINFO(4, "IF(NOT {x}) => IF(x) swapped if/else" << nodep << endl); AstNode* const condp = VN_AS(nodep->condp(), NodeUniop)->lhsp()->unlinkFrBackWithNext(); - AstNode* const ifsp = nodep->ifsp()->unlinkFrBackWithNext(); + AstNode* const thensp = nodep->thensp()->unlinkFrBackWithNext(); AstNode* const elsesp = nodep->elsesp()->unlinkFrBackWithNext(); - AstIf* const ifp = new AstIf(nodep->fileline(), condp, elsesp, ifsp); + AstIf* const ifp = new AstIf(nodep->fileline(), condp, elsesp, thensp); ifp->branchPred(nodep->branchPred().invert()); nodep->replaceWith(ifp); VL_DO_DANGLING(nodep->deleteTree(), nodep); @@ -2941,25 +2939,25 @@ private: UINFO( 4, "IF({a}) ASSIGN({b},{c}) else ASSIGN({b},{d}) => ASSIGN({b}, {a}?{c}:{d})\n"); - AstNodeAssign* const ifp = VN_AS(nodep->ifsp(), NodeAssign); - AstNodeAssign* const elsep = VN_AS(nodep->elsesp(), NodeAssign); - ifp->unlinkFrBack(); + AstNodeAssign* const thensp = VN_AS(nodep->thensp(), NodeAssign); + AstNodeAssign* const elsesp = VN_AS(nodep->elsesp(), NodeAssign); + thensp->unlinkFrBack(); AstNode* const condp = nodep->condp()->unlinkFrBack(); - AstNode* const truep = ifp->rhsp()->unlinkFrBack(); - AstNode* const falsep = elsep->rhsp()->unlinkFrBack(); - ifp->rhsp(new AstCond(truep->fileline(), condp, truep, falsep)); - nodep->replaceWith(ifp); + AstNode* const truep = thensp->rhsp()->unlinkFrBack(); + AstNode* const falsep = elsesp->rhsp()->unlinkFrBack(); + thensp->rhsp(new AstCond(truep->fileline(), condp, truep, falsep)); + nodep->replaceWith(thensp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } else if (false // Disabled, as vpm assertions are faster // without due to short-circuiting && operandIfIf(nodep)) { UINFO(9, "IF({a}) IF({b}) => IF({a} && {b})" << endl); - AstNodeIf* const lowerIfp = VN_AS(nodep->ifsp(), NodeIf); + AstNodeIf* const lowerIfp = VN_AS(nodep->thensp(), NodeIf); AstNode* const condp = nodep->condp()->unlinkFrBack(); - AstNode* const lowerIfsp = lowerIfp->ifsp()->unlinkFrBackWithNext(); + AstNode* const lowerThensp = lowerIfp->thensp()->unlinkFrBackWithNext(); AstNode* const lowerCondp = lowerIfp->condp()->unlinkFrBackWithNext(); nodep->condp(new AstLogAnd(lowerIfp->fileline(), condp, lowerCondp)); - lowerIfp->replaceWith(lowerIfsp); + lowerIfp->replaceWith(lowerThensp); VL_DO_DANGLING(lowerIfp->deleteTree(), lowerIfp); } else if (operandBoolShift(nodep->condp())) { replaceBoolShift(nodep->condp()); @@ -2967,7 +2965,7 @@ private: } } - virtual void visit(AstDisplay* nodep) override { + void visit(AstDisplay* nodep) override { // DISPLAY(SFORMAT(text1)),DISPLAY(SFORMAT(text2)) -> DISPLAY(SFORMAT(text1+text2)) iterateChildren(nodep); if (stmtDisplayDisplay(nodep)) return; @@ -3016,12 +3014,14 @@ private: pformatp->text(pformatp->text() + nformatp->text()); if (!prevp->addNewline() && nodep->addNewline()) pformatp->text(pformatp->text() + "\n"); if (nformatp->exprsp()) pformatp->addExprsp(nformatp->exprsp()->unlinkFrBackWithNext()); - if (nformatp->scopeNamep()) - pformatp->scopeNamep(nformatp->scopeNamep()->unlinkFrBackWithNext()); + if (AstScopeName* const scopeNamep = nformatp->scopeNamep()) { + scopeNamep->unlinkFrBackWithNext(); + pformatp->scopeNamep(scopeNamep); + } VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); return true; } - virtual void visit(AstSFormatF* nodep) override { + void visit(AstSFormatF* nodep) override { // Substitute constants into displays. The main point of this is to // simplify assertion methodologies which call functions with display's. // This eliminates a pile of wide temps, and makes the C a whole lot more readable. @@ -3088,17 +3088,17 @@ private: } } - virtual void visit(AstFuncRef* nodep) override { + void visit(AstFuncRef* nodep) override { iterateChildren(nodep); if (m_params) { // Only parameters force us to do constant function call propagation replaceWithSimulation(nodep); } } - virtual void visit(AstArg* nodep) override { + void visit(AstArg* nodep) override { // replaceWithSimulation on the Arg's parent FuncRef replaces these iterateChildren(nodep); } - virtual void visit(AstWhile* nodep) override { + void visit(AstWhile* nodep) override { const bool oldHasJumpDelay = m_hasJumpDelay; m_hasJumpDelay = false; { iterateChildren(nodep); } @@ -3124,22 +3124,22 @@ private: } } } - virtual void visit(AstInitArray* nodep) override { iterateChildren(nodep); } - virtual void visit(AstInitItem* nodep) override { iterateChildren(nodep); } - virtual void visit(AstUnbounded* nodep) override { iterateChildren(nodep); } + void visit(AstInitArray* nodep) override { iterateChildren(nodep); } + void visit(AstInitItem* nodep) override { iterateChildren(nodep); } + void visit(AstUnbounded* nodep) override { iterateChildren(nodep); } // These are converted by V3Param. Don't constify as we don't want the // from() VARREF to disappear, if any. // If output of a presel didn't get consted, chances are V3Param didn't visit properly - virtual void visit(AstNodePreSel*) override {} + void visit(AstNodePreSel*) override {} // Ignored, can eliminate early - virtual void visit(AstSysIgnore* nodep) override { + void visit(AstSysIgnore* nodep) override { iterateChildren(nodep); if (m_doNConst) VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } // Simplify - virtual void visit(AstBasicDType* nodep) override { + void visit(AstBasicDType* nodep) override { iterateChildren(nodep); nodep->cvtRangeConst(); } @@ -3147,11 +3147,11 @@ private: //----- // Jump elimination - virtual void visit(AstDelay* nodep) override { + void visit(AstDelay* nodep) override { iterateChildren(nodep); m_hasJumpDelay = true; } - virtual void visit(AstJumpGo* nodep) override { + void visit(AstJumpGo* nodep) override { iterateChildren(nodep); // Jump to label where label immediately follows label is not useful if (nodep->labelp() == VN_CAST(nodep->nextp(), JumpLabel)) { @@ -3182,7 +3182,7 @@ private: m_hasJumpDelay = true; } - virtual void visit(AstJumpBlock* nodep) override { + void visit(AstJumpBlock* nodep) override { // Because JumpLabels disable many optimizations, // remove JumpLabels that are not pointed to by any AstJumpGos // Note this assumes all AstJumpGos are underneath the given label; V3Broken asserts this @@ -3301,19 +3301,19 @@ private: TREEOPC("AstAnd {$lhsp.isOne, matchRedundantClean(nodep)}", "DONE") // 1 & (a == b) -> (IData)(a == b) // Trinary ops // Note V3Case::Sel requires Cond to always be conditionally executed in C to prevent core dump! - TREEOP ("AstNodeCond{$condp.isZero, $expr1p, $expr2p}", "replaceWChild(nodep,$expr2p)"); - TREEOP ("AstNodeCond{$condp.isNeqZero, $expr1p, $expr2p}", "replaceWChild(nodep,$expr1p)"); - TREEOPA("AstNodeCond{$condp.isZero, $expr1p.castConst, $expr2p.castConst}", "replaceWChild(nodep,$expr2p)"); - TREEOPA("AstNodeCond{$condp.isNeqZero, $expr1p.castConst, $expr2p.castConst}", "replaceWChild(nodep,$expr1p)"); - TREEOP ("AstNodeCond{$condp, operandsSame($expr1p,,$expr2p)}","replaceWChild(nodep,$expr1p)"); + TREEOP ("AstNodeCond{$condp.isZero, $thenp, $elsep}", "replaceWChild(nodep,$elsep)"); + TREEOP ("AstNodeCond{$condp.isNeqZero, $thenp, $elsep}", "replaceWChild(nodep,$thenp)"); + TREEOPA("AstNodeCond{$condp.isZero, $thenp.castConst, $elsep.castConst}", "replaceWChild(nodep,$elsep)"); + TREEOPA("AstNodeCond{$condp.isNeqZero, $thenp.castConst, $elsep.castConst}", "replaceWChild(nodep,$thenp)"); + TREEOP ("AstNodeCond{$condp, operandsSame($thenp,,$elsep)}","replaceWChild(nodep,$thenp)"); // This visit function here must allow for short-circuiting. TREEOPS("AstCond {$lhsp.isZero}", "replaceWIteratedThs(nodep)"); TREEOPS("AstCond {$lhsp.isNeqZero}", "replaceWIteratedRhs(nodep)"); - TREEOP ("AstCond{$condp.castNot, $expr1p, $expr2p}", "AstCond{$condp->op1p(), $expr2p, $expr1p}"); - TREEOP ("AstNodeCond{$condp.width1, $expr1p.width1, $expr1p.isAllOnes, $expr2p}", "AstLogOr {$condp, $expr2p}"); // a?1:b == a||b - TREEOP ("AstNodeCond{$condp.width1, $expr1p.width1, $expr1p, $expr2p.isZero}", "AstLogAnd{$condp, $expr1p}"); // a?b:0 == a&&b - TREEOP ("AstNodeCond{$condp.width1, $expr1p.width1, $expr1p, $expr2p.isAllOnes}", "AstLogOr {AstNot{$condp}, $expr1p}"); // a?b:1 == ~a||b - TREEOP ("AstNodeCond{$condp.width1, $expr1p.width1, $expr1p.isZero, $expr2p}", "AstLogAnd{AstNot{$condp}, $expr2p}"); // a?0:b == ~a&&b + TREEOP ("AstCond{$condp.castNot, $thenp, $elsep}", "AstCond{$condp->op1p(), $elsep, $thenp}"); + TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp.isAllOnes, $elsep}", "AstLogOr {$condp, $elsep}"); // a?1:b == a||b + TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp, $elsep.isZero}", "AstLogAnd{$condp, $thenp}"); // a?b:0 == a&&b + TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp, $elsep.isAllOnes}", "AstLogOr {AstNot{$condp}, $thenp}"); // a?b:1 == ~a||b + TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp.isZero, $elsep}", "AstLogAnd{AstNot{$condp}, $elsep}"); // a?0:b == ~a&&b TREEOP ("AstNodeCond{!$condp.width1, operandBoolShift(nodep->condp())}", "replaceBoolShift(nodep->condp())"); // Prefer constants on left, since that often needs a shift, it lets // constant red remove the shift @@ -3536,7 +3536,7 @@ private: // Note we can't convert EqCase/NeqCase to Eq/Neq here because that would break 3'b1x1==3'b101 //----- - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { // Default: Just iterate if (m_required) { if (VN_IS(nodep, NodeDType) || VN_IS(nodep, Range) || VN_IS(nodep, SliceSel)) { @@ -3583,7 +3583,7 @@ public: } // clang-format on } - virtual ~ConstVisitor() override { + ~ConstVisitor() override { if (m_doCpp) { if (m_globalPass) { V3Stats::addStat("Optimizations, Const bit op reduction", m_statBitOpReduction); @@ -3664,7 +3664,7 @@ void V3Const::constifyAllLint(AstNetlist* nodep) { ConstVisitor visitor{ConstVisitor::PROC_V_WARN, /* globalPass: */ true}; (void)visitor.mainAcceptEdit(nodep); } // Destruct before checking - V3Global::dumpCheckGlobalTree("const", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("const", 0, dumpTree() >= 3); } void V3Const::constifyCpp(AstNetlist* nodep) { @@ -3673,7 +3673,7 @@ void V3Const::constifyCpp(AstNetlist* nodep) { ConstVisitor visitor{ConstVisitor::PROC_CPP, /* globalPass: */ true}; (void)visitor.mainAcceptEdit(nodep); } // Destruct before checking - V3Global::dumpCheckGlobalTree("const_cpp", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("const_cpp", 0, dumpTree() >= 3); } AstNode* V3Const::constifyEdit(AstNode* nodep) { @@ -3697,7 +3697,7 @@ void V3Const::constifyAllLive(AstNetlist* nodep) { ConstVisitor visitor{ConstVisitor::PROC_LIVE, /* globalPass: */ true}; (void)visitor.mainAcceptEdit(nodep); } // Destruct before checking - V3Global::dumpCheckGlobalTree("const", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("const", 0, dumpTree() >= 3); } void V3Const::constifyAll(AstNetlist* nodep) { @@ -3707,7 +3707,7 @@ void V3Const::constifyAll(AstNetlist* nodep) { ConstVisitor visitor{ConstVisitor::PROC_V_EXPENSIVE, /* globalPass: */ true}; (void)visitor.mainAcceptEdit(nodep); } // Destruct before checking - V3Global::dumpCheckGlobalTree("const", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("const", 0, dumpTree() >= 3); } AstNode* V3Const::constifyExpensiveEdit(AstNode* nodep) { diff --git a/src/V3Coverage.cpp b/src/V3Coverage.cpp index e03be42d4..324e6f7a4 100644 --- a/src/V3Coverage.cpp +++ b/src/V3Coverage.cpp @@ -35,6 +35,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Coverage state, as a visitor of each AstNode @@ -86,7 +88,6 @@ private: m_handleLines; // All line numbers for a given m_stateHandle // METHODS - VL_DEBUG_FUNC; // Declare debug() const char* varIgnoreToggle(AstVar* nodep) { // Return true if this shouldn't be traced @@ -119,7 +120,7 @@ private: AstCoverDecl* const declp = new AstCoverDecl(fl, page, comment, linescov, offset); declp->hier(hier); - m_modp->addStmtp(declp); + m_modp->addStmtsp(declp); UINFO(9, "new " << declp << endl); AstCoverInc* const incp = new AstCoverInc(fl, declp); @@ -128,13 +129,13 @@ private: incp->findUInt32DType()); varp->trace(true); varp->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); - m_modp->addStmtp(varp); + m_modp->addStmtsp(varp); UINFO(5, "New coverage trace: " << varp << endl); AstAssign* const assp = new AstAssign( incp->fileline(), new AstVarRef(incp->fileline(), varp, VAccess::WRITE), new AstAdd(incp->fileline(), new AstVarRef(incp->fileline(), varp, VAccess::READ), new AstConst(incp->fileline(), AstConst::WidthedValue(), 32, 1))); - incp->addNext(assp); + AstNode::addNext(incp, assp); } return incp; } @@ -209,7 +210,7 @@ private: } // VISITORS - BOTH - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { const AstNodeModule* const origModp = m_modp; VL_RESTORER(m_modp); VL_RESTORER(m_state); @@ -227,9 +228,9 @@ private: } } - virtual void visit(AstNodeProcedure* nodep) override { iterateProcedure(nodep); } - virtual void visit(AstWhile* nodep) override { iterateProcedure(nodep); } - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstNodeProcedure* nodep) override { iterateProcedure(nodep); } + void visit(AstWhile* nodep) override { iterateProcedure(nodep); } + void visit(AstNodeFTask* nodep) override { if (!nodep->dpiImport()) iterateProcedure(nodep); } void iterateProcedure(AstNode* nodep) { @@ -245,11 +246,11 @@ private: = newCoverInc(nodep->fileline(), "", "v_line", "block", linesCov(m_state, nodep), 0, traceNameForLine(nodep, "block")); if (AstNodeProcedure* const itemp = VN_CAST(nodep, NodeProcedure)) { - itemp->addStmtp(newp); + itemp->addStmtsp(newp); } else if (AstNodeFTask* const itemp = VN_CAST(nodep, NodeFTask)) { itemp->addStmtsp(newp); } else if (AstWhile* const itemp = VN_CAST(nodep, While)) { - itemp->addBodysp(newp); + itemp->addStmtsp(newp); } else { nodep->v3fatalSrc("Bad node type"); } @@ -258,7 +259,7 @@ private: } // VISITORS - TOGGLE COVERAGE - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { iterateChildren(nodep); if (m_modp && !m_inToggleOff && !m_state.m_inModOff && nodep->fileline()->coverageOn() && v3Global.opt.coverageToggle()) { @@ -283,7 +284,7 @@ private: AstVar* const chgVarp = new AstVar(nodep->fileline(), VVarType::MODULETEMP, newvarname, nodep); chgVarp->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); - m_modp->addStmtp(chgVarp); + m_modp->addStmtsp(chgVarp); // Create bucket for each dimension * bit. // This is necessarily an O(n^2) expansion, which is why @@ -304,7 +305,7 @@ private: newCoverInc(varp->fileline(), "", "v_toggle", varp->name() + above.m_comment, "", 0, ""), above.m_varRefp->cloneTree(true), above.m_chgRefp->cloneTree(true)); - m_modp->addStmtp(newp); + m_modp->addStmtsp(newp); } void toggleVarRecurse(AstNodeDType* dtypep, int depth, // per-iteration @@ -383,12 +384,12 @@ private: // VISITORS - LINE COVERAGE // Note not AstNodeIf; other types don't get covered - virtual void visit(AstIf* nodep) override { + void visit(AstIf* nodep) override { UINFO(4, " IF: " << nodep << endl); if (m_state.m_on) { // An else-if. When we iterate the if, use "elsif" marking const bool elsif - = nodep->ifsp() && VN_IS(nodep->elsesp(), If) && !nodep->elsesp()->nextp(); + = nodep->thensp() && VN_IS(nodep->elsesp(), If) && !nodep->elsesp()->nextp(); if (elsif) VN_AS(nodep->elsesp(), If)->user1(true); const bool first_elsif = !nodep->user1() && elsif; const bool cont_elsif = nodep->user1() && elsif; @@ -403,7 +404,7 @@ private: CheckState elseState; { createHandle(nodep); - iterateAndNextNull(nodep->ifsp()); + iterateAndNextNull(nodep->thensp()); lineTrack(nodep); ifState = m_state; } @@ -422,9 +423,9 @@ private: // Normal if. Linecov shows what's inside the if (not condition that is // always executed) UINFO(4, " COVER-branch: " << nodep << endl); - nodep->addIfsp(newCoverInc(nodep->fileline(), "", "v_branch", "if", - linesCov(ifState, nodep), 0, - traceNameForLine(nodep, "if"))); + nodep->addThensp(newCoverInc(nodep->fileline(), "", "v_branch", "if", + linesCov(ifState, nodep), 0, + traceNameForLine(nodep, "if"))); // The else has a column offset of 1 to uniquify it relative to the if // As "if" and "else" are more than one character wide, this won't overlap // another token @@ -436,18 +437,18 @@ private: else if (first_elsif || cont_elsif) { UINFO(4, " COVER-elsif: " << nodep << endl); if (ifState.lineCoverageOn(nodep)) { - nodep->addIfsp(newCoverInc(nodep->fileline(), "", "v_line", "elsif", - linesCov(ifState, nodep), 0, - traceNameForLine(nodep, "elsif"))); + nodep->addThensp(newCoverInc(nodep->fileline(), "", "v_line", "elsif", + linesCov(ifState, nodep), 0, + traceNameForLine(nodep, "elsif"))); } // and we don't insert the else as the child if-else will do so } else { // Cover as separate blocks (not a branch as is not two-legged) if (ifState.lineCoverageOn(nodep)) { UINFO(4, " COVER-half-if: " << nodep << endl); - nodep->addIfsp(newCoverInc(nodep->fileline(), "", "v_line", "if", - linesCov(ifState, nodep), 0, - traceNameForLine(nodep, "if"))); + nodep->addThensp(newCoverInc(nodep->fileline(), "", "v_line", "if", + linesCov(ifState, nodep), 0, + traceNameForLine(nodep, "if"))); } if (elseState.lineCoverageOn(nodep)) { UINFO(4, " COVER-half-el: " << nodep << endl); @@ -460,7 +461,7 @@ private: } UINFO(9, " done HANDLE " << m_state.m_handle << " for " << nodep << endl); } - virtual void visit(AstCaseItem* nodep) override { + void visit(AstCaseItem* nodep) override { // We don't add an explicit "default" coverage if not provided, // as we already have a warning when there is no default. UINFO(4, " CASEI: " << nodep << endl); @@ -468,38 +469,38 @@ private: VL_RESTORER(m_state); { createHandle(nodep); - iterateAndNextNull(nodep->bodysp()); + iterateAndNextNull(nodep->stmtsp()); if (m_state.lineCoverageOn(nodep)) { // if the case body didn't disable it lineTrack(nodep); UINFO(4, " COVER: " << nodep << endl); - nodep->addBodysp(newCoverInc(nodep->fileline(), "", "v_line", "case", + nodep->addStmtsp(newCoverInc(nodep->fileline(), "", "v_line", "case", linesCov(m_state, nodep), 0, traceNameForLine(nodep, "case"))); } } } } - virtual void visit(AstCover* nodep) override { + void visit(AstCover* nodep) override { UINFO(4, " COVER: " << nodep << endl); VL_RESTORER(m_state); { m_state.m_on = true; // Always do cover blocks, even if there's a $stop createHandle(nodep); iterateChildren(nodep); - if (!nodep->coverincp() && v3Global.opt.coverageUser()) { + if (!nodep->coverincsp() && v3Global.opt.coverageUser()) { // Note the name may be overridden by V3Assert processing lineTrack(nodep); - nodep->coverincp(newCoverInc(nodep->fileline(), m_beginHier, "v_user", "cover", - linesCov(m_state, nodep), 0, - m_beginHier + "_vlCoverageUserTrace")); + nodep->addCoverincsp(newCoverInc(nodep->fileline(), m_beginHier, "v_user", "cover", + linesCov(m_state, nodep), 0, + m_beginHier + "_vlCoverageUserTrace")); } } } - virtual void visit(AstStop* nodep) override { + void visit(AstStop* nodep) override { UINFO(4, " STOP: " << nodep << endl); m_state.m_on = false; } - virtual void visit(AstPragma* nodep) override { + void visit(AstPragma* nodep) override { if (nodep->pragType() == VPragmaType::COVERAGE_BLOCK_OFF) { // Skip all NEXT nodes under this block, and skip this if/case branch UINFO(4, " OFF: h" << m_state.m_handle << " " << nodep << endl); @@ -510,7 +511,7 @@ private: lineTrack(nodep); } } - virtual void visit(AstBegin* nodep) override { + void visit(AstBegin* nodep) override { // Record the hierarchy of any named begins, so we can apply to user // coverage points. This is because there may be cov points inside // generate blocks; each point should get separate consideration. @@ -529,7 +530,7 @@ private: } // VISITORS - BOTH - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { iterateChildren(nodep); lineTrack(nodep); } @@ -537,7 +538,7 @@ private: public: // CONSTRUCTORS explicit CoverageVisitor(AstNetlist* rootp) { iterateChildren(rootp); } - virtual ~CoverageVisitor() override = default; + ~CoverageVisitor() override = default; }; //###################################################################### @@ -546,5 +547,5 @@ public: void V3Coverage::coverage(AstNetlist* rootp) { UINFO(2, __FUNCTION__ << ": " << endl); { CoverageVisitor{rootp}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("coverage", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("coverage", 0, dumpTree() >= 3); } diff --git a/src/V3CoverageJoin.cpp b/src/V3CoverageJoin.cpp index 1b16971d6..d5571a7a7 100644 --- a/src/V3CoverageJoin.cpp +++ b/src/V3CoverageJoin.cpp @@ -28,6 +28,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // CoverageJoin state, as a visitor of each AstNode @@ -42,7 +44,6 @@ private: VDouble0 m_statToggleJoins; // Statistic tracking // METHODS - VL_DEBUG_FUNC; // Declare debug() void detectDuplicates() { UINFO(9, "Finding duplicates\n"); @@ -88,24 +89,24 @@ private: } // VISITORS - virtual void visit(AstNetlist* nodep) override { + void visit(AstNetlist* nodep) override { // Find all Coverage's iterateChildren(nodep); // Simplify detectDuplicates(); } - virtual void visit(AstCoverToggle* nodep) override { + void visit(AstCoverToggle* nodep) override { m_toggleps.push_back(nodep); iterateChildren(nodep); } //-------------------- - virtual void visit(AstNodeMath*) override {} // Accelerate - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit CoverageJoinVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~CoverageJoinVisitor() override { + ~CoverageJoinVisitor() override { V3Stats::addStat("Coverage, Toggle points joined", m_statToggleJoins); } }; @@ -116,5 +117,5 @@ public: void V3CoverageJoin::coverageJoin(AstNetlist* rootp) { UINFO(2, __FUNCTION__ << ": " << endl); { CoverageJoinVisitor{rootp}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("coveragejoin", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("coveragejoin", 0, dumpTree() >= 3); } diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index 5c6c11fb4..83ecf5ffa 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -44,6 +44,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Dead state, as a visitor of each AstNode @@ -78,7 +80,6 @@ private: bool m_sideEffect = false; // Side effects discovered in assign RHS // METHODS - VL_DEBUG_FUNC; // Declare debug() void checkAll(AstNode* nodep) { if (nodep != nodep->dtypep()) { // NodeDTypes reference themselves @@ -102,7 +103,7 @@ private: } // VISITORS - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { if (m_modp) m_modp->user1Inc(); // e.g. Class under Package VL_RESTORER(m_modp); { @@ -120,12 +121,12 @@ private: } } } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { iterateChildren(nodep); checkAll(nodep); if (nodep->scopep()) nodep->scopep()->user1Inc(); } - virtual void visit(AstScope* nodep) override { + void visit(AstScope* nodep) override { iterateChildren(nodep); checkAll(nodep); if (nodep->aboveScopep()) nodep->aboveScopep()->user1Inc(); @@ -136,14 +137,14 @@ private: m_scopesp.push_back(nodep); } } - virtual void visit(AstCell* nodep) override { + void visit(AstCell* nodep) override { iterateChildren(nodep); checkAll(nodep); m_cellsp.push_back(nodep); nodep->modp()->user1Inc(); } - virtual void visit(AstNodeVarRef* nodep) override { + void visit(AstNodeVarRef* nodep) override { // Note NodeAssign skips calling this in some cases iterateChildren(nodep); checkAll(nodep); @@ -155,7 +156,7 @@ private: if (nodep->varp()) nodep->varp()->user1Inc(); if (nodep->classOrPackagep()) nodep->classOrPackagep()->user1Inc(); } - virtual void visit(AstNodeFTaskRef* nodep) override { + void visit(AstNodeFTaskRef* nodep) override { iterateChildren(nodep); checkAll(nodep); if (nodep->classOrPackagep()) { @@ -166,11 +167,11 @@ private: } } } - virtual void visit(AstMethodCall* nodep) override { + void visit(AstMethodCall* nodep) override { iterateChildren(nodep); checkAll(nodep); } - virtual void visit(AstRefDType* nodep) override { + void visit(AstRefDType* nodep) override { iterateChildren(nodep); checkDType(nodep); checkAll(nodep); @@ -184,7 +185,7 @@ private: } } } - virtual void visit(AstClassRefDType* nodep) override { + void visit(AstClassRefDType* nodep) override { iterateChildren(nodep); checkDType(nodep); checkAll(nodep); @@ -197,12 +198,12 @@ private: } if (nodep->classp()) nodep->classp()->user1Inc(); } - virtual void visit(AstNodeDType* nodep) override { + void visit(AstNodeDType* nodep) override { iterateChildren(nodep); checkDType(nodep); checkAll(nodep); } - virtual void visit(AstEnumItemRef* nodep) override { + void visit(AstEnumItemRef* nodep) override { iterateChildren(nodep); checkAll(nodep); if (nodep->classOrPackagep()) { @@ -214,13 +215,13 @@ private: } checkAll(nodep); } - virtual void visit(AstMemberSel* nodep) override { + void visit(AstMemberSel* nodep) override { iterateChildren(nodep); if (nodep->varp()) nodep->varp()->user1Inc(); if (nodep->fromp()->dtypep()) nodep->fromp()->dtypep()->user1Inc(); // classref checkAll(nodep); } - virtual void visit(AstModport* nodep) override { + void visit(AstModport* nodep) override { iterateChildren(nodep); if (m_elimCells) { if (!nodep->varsp()) { @@ -230,14 +231,14 @@ private: } checkAll(nodep); } - virtual void visit(AstSelLoopVars* nodep) override { + void visit(AstSelLoopVars* nodep) override { // Var under a SelLoopVars means we haven't called V3Width to remove them yet VL_RESTORER(m_selloopvarsp); m_selloopvarsp = nodep; iterateChildren(nodep); checkAll(nodep); } - virtual void visit(AstTypedef* nodep) override { + void visit(AstTypedef* nodep) override { iterateChildren(nodep); if (m_elimCells && !nodep->attrPublic()) { VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); @@ -248,20 +249,20 @@ private: // Normal modules may disappear, e.g. if they are parameterized then removed if (nodep->attrPublic() && m_modp && VN_IS(m_modp, Package)) m_modp->user1Inc(); } - virtual void visit(AstVarScope* nodep) override { + void visit(AstVarScope* nodep) override { iterateChildren(nodep); checkAll(nodep); if (nodep->scopep()) nodep->scopep()->user1Inc(); if (mightElimVar(nodep->varp())) m_vscsp.push_back(nodep); } - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { iterateChildren(nodep); checkAll(nodep); if (nodep->isSigPublic() && m_modp && VN_IS(m_modp, Package)) m_modp->user1Inc(); if (m_selloopvarsp) nodep->user1Inc(); if (mightElimVar(nodep)) m_varsp.push_back(nodep); } - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { // See if simple assignments to variables may be eliminated because // that variable is never used. // Similar code in V3Life @@ -284,7 +285,7 @@ private: } //----- - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { if (nodep->isOutputter()) m_sideEffect = true; iterateChildren(nodep); checkAll(nodep); @@ -446,7 +447,7 @@ public: // We may have removed some datatypes, cleanup nodep->typeTablep()->repairCache(); } - virtual ~DeadVisitor() override = default; + ~DeadVisitor() override = default; }; //###################################################################### @@ -455,30 +456,29 @@ public: void V3Dead::deadifyModules(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DeadVisitor{nodep, false, false, false, false}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("deadModules", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6); + V3Global::dumpCheckGlobalTree("deadModules", 0, dumpTree() >= 6); } void V3Dead::deadifyDTypes(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DeadVisitor{nodep, false, true, false, false}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("deadDtypes", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("deadDtypes", 0, dumpTree() >= 3); } void V3Dead::deadifyDTypesScoped(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DeadVisitor{nodep, false, true, true, false}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0, - v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0, dumpTree() >= 3); } void V3Dead::deadifyAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DeadVisitor{nodep, true, true, false, true}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("deadAll", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("deadAll", 0, dumpTree() >= 3); } void V3Dead::deadifyAllScoped(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DeadVisitor{nodep, true, true, true, true}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("deadAllScoped", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("deadAllScoped", 0, dumpTree() >= 3); } diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index ce06a16a2..6a4e89ed8 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -61,6 +61,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Delayed state, as a visitor of each AstNode @@ -102,7 +104,6 @@ private: std::unordered_map m_scopeVecMap; // Next var number for each scope // METHODS - VL_DEBUG_FUNC; // Declare debug() void markVarUsage(AstNodeVarRef* nodep, bool blocking) { // Ignore if warning is disabled on this reference (used by V3Force). @@ -153,13 +154,13 @@ private: varp = new AstVar(oldvarscp->fileline(), VVarType::BLOCKTEMP, name, VFlagBitPacked(), width); } - addmodp->addStmtp(varp); + addmodp->addStmtsp(varp); m_modVarMap.emplace(std::make_pair(addmodp, name), varp); } AstVarScope* const varscp = new AstVarScope(oldvarscp->fileline(), oldvarscp->scopep(), varp); - oldvarscp->scopep()->addVarp(varscp); + oldvarscp->scopep()->addVarsp(varscp); return varscp; } @@ -356,33 +357,33 @@ private: postLogicp = new AstIf(nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, VAccess::READ)); UINFO(9, " Created " << postLogicp << endl); - finalp->addStmtp(postLogicp); + finalp->addStmtsp(postLogicp); finalp->user3p(setvscp); // Remember IF's vset variable finalp->user4p(postLogicp); // and the associated IF, as we may be able to reuse it } - postLogicp->addIfsp(new AstAssign(nodep->fileline(), selectsp, valreadp)); + postLogicp->addThensp(new AstAssign(nodep->fileline(), selectsp, valreadp)); return newlhsp; } // VISITORS - virtual void visit(AstNetlist* nodep) override { + void visit(AstNetlist* nodep) override { // VV***** We reset all userp() on the netlist m_modVarMap.clear(); iterateChildren(nodep); } - virtual void visit(AstScope* nodep) override { + void visit(AstScope* nodep) override { UINFO(4, " MOD " << nodep << endl); AstNode::user3ClearTree(); iterateChildren(nodep); } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { VL_RESTORER(m_cfuncp); { m_cfuncp = nodep; iterateChildren(nodep); } } - virtual void visit(AstActive* nodep) override { + void visit(AstActive* nodep) override { m_activep = nodep; VL_RESTORER(m_inInitial); { @@ -392,7 +393,7 @@ private: iterateChildren(nodep); } } - virtual void visit(AstAssignDly* nodep) override { + void visit(AstAssignDly* nodep) override { m_inDly = true; m_nextDlyp = VN_CAST(nodep->nextp(), AssignDly); // Next assignment in same block, maybe nullptr. @@ -426,7 +427,7 @@ private: m_nextDlyp = nullptr; } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { if (!nodep->user2Inc()) { // Not done yet if (m_inDly && nodep->access().isWriteOrRW()) { UINFO(4, "AssignDlyVar: " << nodep << endl); @@ -488,18 +489,18 @@ private: } } - virtual void visit(AstNodeReadWriteMem* nodep) override { + void visit(AstNodeReadWriteMem* nodep) override { VL_RESTORER(m_ignoreBlkAndNBlk); m_ignoreBlkAndNBlk = true; // $readmem/$writemem often used in mem models // so we will suppress BLKANDNBLK warnings iterateChildren(nodep); } - virtual void visit(AstNodeFor* nodep) override { // LCOV_EXCL_LINE + void visit(AstNodeFor* nodep) override { // LCOV_EXCL_LINE nodep->v3fatalSrc( "For statements should have been converted to while statements in V3Begin"); } - virtual void visit(AstWhile* nodep) override { + void visit(AstWhile* nodep) override { VL_RESTORER(m_inLoop); { m_inLoop = true; @@ -508,12 +509,12 @@ private: } //-------------------- - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit DelayedVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~DelayedVisitor() override { + ~DelayedVisitor() override { V3Stats::addStat("Optimizations, Delayed shared-sets", m_statSharedSet); } }; @@ -524,5 +525,5 @@ public: void V3Delayed::delayedAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DelayedVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("delayed", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("delayed", 0, dumpTree() >= 3); } diff --git a/src/V3Depth.cpp b/src/V3Depth.cpp index 7b81e22ca..489d36b7d 100644 --- a/src/V3Depth.cpp +++ b/src/V3Depth.cpp @@ -34,6 +34,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### class DepthVisitor final : public VNVisitor { @@ -49,7 +51,6 @@ private: V3UniqueNames m_tempNames; // For generating unique temporary variable names // METHODS - VL_DEBUG_FUNC; // Declare debug() void createDeepTemp(AstNode* nodep) { UINFO(6, " Deep " << nodep << endl); @@ -73,7 +74,7 @@ private: } // VISITORS - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { VL_RESTORER(m_cfuncp); VL_RESTORER(m_mtaskbodyp); { @@ -85,7 +86,7 @@ private: iterateChildren(nodep); } } - virtual void visit(AstMTaskBody* nodep) override { + void visit(AstMTaskBody* nodep) override { VL_RESTORER(m_cfuncp); VL_RESTORER(m_mtaskbodyp); { @@ -106,7 +107,7 @@ private: iterateChildren(nodep); } } - virtual void visit(AstNodeStmt* nodep) override { + void visit(AstNodeStmt* nodep) override { if (!nodep->isStatement()) { iterateChildren(nodep); } else { @@ -114,8 +115,8 @@ private: } } // Operators - virtual void visit(AstNodeTermop* nodep) override {} - virtual void visit(AstNodeMath* nodep) override { + void visit(AstNodeTermop* nodep) override {} + void visit(AstNodeMath* nodep) override { // We have some operator defines that use 2 parens, so += 2. { VL_RESTORER(m_depth); @@ -142,19 +143,19 @@ private: m_cfuncp->isStatic(false); } } - virtual void visit(AstUCFunc* nodep) override { + void visit(AstUCFunc* nodep) override { needNonStaticFunc(nodep); iterateChildren(nodep); } - virtual void visit(AstUCStmt* nodep) override { + void visit(AstUCStmt* nodep) override { needNonStaticFunc(nodep); visitStmt(nodep); } //-------------------- // Default: Just iterate - virtual void visit(AstVar*) override {} // Don't hit varrefs under vars - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstVar*) override {} // Don't hit varrefs under vars + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -162,7 +163,7 @@ public: : m_tempNames{"__Vdeeptemp"} { iterate(nodep); } - virtual ~DepthVisitor() override = default; + ~DepthVisitor() override = default; }; //###################################################################### @@ -171,5 +172,5 @@ public: void V3Depth::depthAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DepthVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("depth", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6); + V3Global::dumpCheckGlobalTree("depth", 0, dumpTree() >= 6); } diff --git a/src/V3DepthBlock.cpp b/src/V3DepthBlock.cpp index 22da37e91..9399e78e0 100644 --- a/src/V3DepthBlock.cpp +++ b/src/V3DepthBlock.cpp @@ -31,6 +31,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### class DepthBlockVisitor final : public VNVisitor { @@ -44,7 +46,6 @@ private: int m_deepNum = 0; // How many functions made // METHODS - VL_DEBUG_FUNC; // Declare debug() AstCFunc* createDeepFunc(AstNode* nodep) { VNRelinker relinkHandle; @@ -57,7 +58,7 @@ private: funcp->isStatic(m_cfuncp->isStatic()); funcp->isLoose(m_cfuncp->isLoose()); funcp->addStmtsp(nodep); - scopep->addActivep(funcp); + scopep->addBlocksp(funcp); // Call sub function at the point where the body was removed from AstCCall* const callp = new AstCCall(nodep->fileline(), funcp); if (VN_IS(m_modp, Class)) { @@ -71,7 +72,7 @@ private: } // VISITORS - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { UINFO(4, " MOD " << nodep << endl); VL_RESTORER(m_modp); { @@ -80,7 +81,7 @@ private: iterateChildren(nodep); } } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { // We recurse into this. VL_RESTORER(m_depth); VL_RESTORER(m_cfuncp); @@ -106,7 +107,7 @@ private: } m_depth--; } - virtual void visit(AstNodeStmt* nodep) override { + void visit(AstNodeStmt* nodep) override { if (!nodep->isStatement()) { iterateChildren(nodep); } else { @@ -114,15 +115,15 @@ private: } } - virtual void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNodeMath*) override {} // Accelerate //-------------------- - virtual void visit(AstVar*) override {} // Don't hit varrefs under vars - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstVar*) override {} // Don't hit varrefs under vars + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit DepthBlockVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~DepthBlockVisitor() override = default; + ~DepthBlockVisitor() override = default; }; //###################################################################### @@ -131,5 +132,5 @@ public: void V3DepthBlock::depthBlockAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DepthBlockVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("deepblock", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("deepblock", 0, dumpTree() >= 3); } diff --git a/src/V3Descope.cpp b/src/V3Descope.cpp index 4fe90837f..b93c0b947 100644 --- a/src/V3Descope.cpp +++ b/src/V3Descope.cpp @@ -33,6 +33,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### class DescopeVisitor final : public VNVisitor { @@ -53,7 +55,6 @@ private: FuncMmap m_modFuncs; // Name of public functions added // METHODS - VL_DEBUG_FUNC; // Declare debug() static bool modIsSingleton(AstNodeModule* modp) { // True iff there's exactly one instance of this module in the design (including top). @@ -139,14 +140,14 @@ private: UINFO(6, " at " << newfuncp->argTypes() << " und " << funcp->argTypes() << endl); funcp->declPrivate(true); - AstNode* argsp = nullptr; + AstVarRef* argsp = nullptr; for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp = stmtp->nextp()) { if (AstVar* const portp = VN_CAST(stmtp, Var)) { if (portp->isIO() && !portp->isFuncReturn()) { - AstNode* const newp = new AstVarRef( + AstVarRef* const newp = new AstVarRef( portp->fileline(), portp, portp->isWritable() ? VAccess::WRITE : VAccess::READ); - argsp = argsp ? argsp->addNextNull(newp) : newp; + argsp = AstNode::addNext(argsp, newp); } } } @@ -185,11 +186,11 @@ private: } // VISITORS - virtual void visit(AstNetlist* nodep) override { + void visit(AstNetlist* nodep) override { nodep->dpiExportTriggerp(nullptr); iterateChildren(nodep); } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { VL_RESTORER(m_modp); { m_modp = nodep; @@ -199,17 +200,17 @@ private: makePublicFuncWrappers(); } } - virtual void visit(AstScope* nodep) override { + void visit(AstScope* nodep) override { m_scopep = nodep; iterateChildren(nodep); m_scopep = nullptr; } - virtual void visit(AstVarScope* nodep) override { + void visit(AstVarScope* nodep) override { // Delete the varscope when we're finished nodep->unlinkFrBack(); pushDeletep(nodep); } - virtual void visit(AstNodeVarRef* nodep) override { + void visit(AstNodeVarRef* nodep) override { iterateChildren(nodep); if (!nodep->varScopep()) { UASSERT_OBJ(nodep->varp()->isFuncLocal(), nodep, @@ -233,7 +234,7 @@ private: nodep->varScopep(nullptr); UINFO(9, " refout " << nodep << " selfPtr=" << nodep->selfPointer() << endl); } - virtual void visit(AstCCall* nodep) override { + void visit(AstCCall* nodep) override { // UINFO(9, " " << nodep << endl); iterateChildren(nodep); // Convert the hierch name @@ -243,9 +244,9 @@ private: // Can't do this, as we may have more calls later // nodep->funcp()->scopep(nullptr); } - virtual void visit(AstCMethodCall* nodep) override { iterateChildren(nodep); } - virtual void visit(AstCNew* nodep) override { iterateChildren(nodep); } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCMethodCall* nodep) override { iterateChildren(nodep); } + void visit(AstCNew* nodep) override { iterateChildren(nodep); } + void visit(AstCFunc* nodep) override { VL_RESTORER(m_funcp); if (!nodep->user1()) { // Static functions should have been moved under the corresponding AstClassPackage @@ -257,7 +258,7 @@ private: // If it's under a scope, move it up to the top if (m_scopep) { nodep->unlinkFrBack(); - m_modp->addStmtp(nodep); + m_modp->addStmtsp(nodep); if (nodep->funcPublic()) { // There may be multiple public functions by the same name; @@ -268,13 +269,13 @@ private: } } } - virtual void visit(AstVar*) override {} - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstVar*) override {} + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit DescopeVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~DescopeVisitor() override = default; + ~DescopeVisitor() override = default; }; //###################################################################### @@ -283,5 +284,5 @@ public: void V3Descope::descopeAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DescopeVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("descope", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("descope", 0, dumpTree() >= 3); } diff --git a/src/V3DupFinder.cpp b/src/V3DupFinder.cpp index 17c498646..70647a1d1 100644 --- a/src/V3DupFinder.cpp +++ b/src/V3DupFinder.cpp @@ -28,6 +28,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // V3DupFinder class functions @@ -98,7 +100,5 @@ void V3DupFinder::dumpFile(const string& filename, bool tree) { } void V3DupFinder::dumpFilePrefixed(const string& nameComment, bool tree) { - if (v3Global.opt.dumpTree()) { // - dumpFile(v3Global.debugFilename(nameComment) + ".hash", tree); - } + if (dump()) dumpFile(v3Global.debugFilename(nameComment) + ".hash", tree); } diff --git a/src/V3DupFinder.h b/src/V3DupFinder.h index 3853fa35f..9bc8df81b 100644 --- a/src/V3DupFinder.h +++ b/src/V3DupFinder.h @@ -59,7 +59,6 @@ public: } // METHODS - VL_DEBUG_FUNC; // Declare debug() // Expose minimal set of superclass interface using Super::begin; diff --git a/src/V3EmitCBase.cpp b/src/V3EmitCBase.cpp index 1e3e9383f..40198fa76 100644 --- a/src/V3EmitCBase.cpp +++ b/src/V3EmitCBase.cpp @@ -57,11 +57,11 @@ string EmitCBaseVisitor::funcNameProtect(const AstCFunc* nodep, const AstNodeMod return name; } -AstCFile* EmitCBaseVisitor::newCFile(const string& filename, bool slow, bool source) { +AstCFile* EmitCBaseVisitor::newCFile(const string& filename, bool slow, bool source, bool add) { AstCFile* const cfilep = new AstCFile(v3Global.rootp()->fileline(), filename); cfilep->slow(slow); cfilep->source(source); - v3Global.rootp()->addFilesp(cfilep); + if (add) v3Global.rootp()->addFilesp(cfilep); return cfilep; } diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index 66b954f35..ca293eef1 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -100,7 +100,7 @@ public: && (varp->basicp() && !varp->basicp()->isOpaque()); // Aggregates can't be anon } - static AstCFile* newCFile(const string& filename, bool slow, bool source); + static AstCFile* newCFile(const string& filename, bool slow, bool source, bool add = true); string cFuncArgs(const AstCFunc* nodep); void emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp, bool withScope); void emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, bool cLinkage = false); @@ -110,7 +110,7 @@ public: // CONSTRUCTORS EmitCBaseVisitor() = default; - virtual ~EmitCBaseVisitor() override = default; + ~EmitCBaseVisitor() override = default; }; #endif // guard diff --git a/src/V3EmitCConstInit.h b/src/V3EmitCConstInit.h index 6c02bf099..fbcac4c16 100644 --- a/src/V3EmitCConstInit.h +++ b/src/V3EmitCConstInit.h @@ -32,7 +32,6 @@ class EmitCConstInit VL_NOT_FINAL : public EmitCBaseVisitor { uint32_t m_unpackedWord = 0; // METHODS - VL_DEBUG_FUNC; // Declare debug() uint32_t tabModulus(AstNodeDType* dtypep) { const uint32_t elemBytes = dtypep->widthTotalBytes(); @@ -45,7 +44,7 @@ class EmitCConstInit VL_NOT_FINAL : public EmitCBaseVisitor { protected: // VISITORS - virtual void visit(AstInitArray* nodep) override { + void visit(AstInitArray* nodep) override { VL_RESTORER(m_inUnpacked); VL_RESTORER(m_unpackedWord); m_inUnpacked = true; @@ -94,11 +93,11 @@ protected: } } - virtual void visit(AstInitItem* nodep) override { // LCOV_EXCL_START + void visit(AstInitItem* nodep) override { // LCOV_EXCL_START nodep->v3fatal("Handled by AstInitArray"); } // LCOV_EXCL_STOP - virtual void visit(AstConst* nodep) override { + void visit(AstConst* nodep) override { const V3Number& num = nodep->num(); UASSERT_OBJ(!num.isFourState(), nodep, "4-state value in constant pool"); const AstNodeDType* const dtypep = nodep->dtypep(); @@ -145,7 +144,7 @@ protected: } // Default - virtual void visit(AstNode* nodep) override { // LCOV_EXCL_START + void visit(AstNode* nodep) override { // LCOV_EXCL_START nodep->v3fatalSrc("Unknown node type reached EmitCConstInit: " << nodep->prettyTypeName()); } // LCOV_EXCL_STOP }; diff --git a/src/V3EmitCConstPool.cpp b/src/V3EmitCConstPool.cpp index 2fd22ccc4..672d2cabb 100644 --- a/src/V3EmitCConstPool.cpp +++ b/src/V3EmitCConstPool.cpp @@ -27,6 +27,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Const pool emitter @@ -38,7 +40,6 @@ class EmitCConstPool final : public EmitCConstInit { VDouble0 m_constsEmitted; // METHODS - VL_DEBUG_FUNC; // Declare debug() V3OutCFile* newOutCFile() const { const string fileName = v3Global.opt.makeDir() + "/" + topClassName() + "__ConstPool_" @@ -100,7 +101,7 @@ class EmitCConstPool final : public EmitCConstInit { } // VISITORS - virtual void visit(AstConst* nodep) override { + void visit(AstConst* nodep) override { m_outFileSize += nodep->num().isString() ? 10 : nodep->isWide() ? nodep->widthWords() : 1; EmitCConstInit::visit(nodep); } diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 9d863c7e5..7a9abae9f 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -36,18 +36,20 @@ constexpr int EMITC_NUM_CONSTW = 8; class EmitCLazyDecls final : public VNVisitor { // NODE STATE/TYPES - // AstNode::user2() -> bool. Already emitted decl for symbols. - const VNUser2InUse m_inuser2; + // None allowed to support threaded emitting // MEMBERS std::unordered_set m_emittedManually; // Set of names already declared manually. EmitCBaseVisitor& m_emitter; // For access to file output bool m_needsBlankLine = false; // Emit blank line if any declarations were emitted (cosmetic) + std::set m_emitted; // -> in set. Already emitted decl for symbols. // METHODS + bool declaredOnce(AstNode* nodep) { return m_emitted.insert(nodep).second; } + void lazyDeclare(AstCFunc* funcp) { // Already declared in this compilation unit - if (funcp->user2SetOnce()) return; + if (!declaredOnce(funcp)) return; // Check if this kind of function is lazily declared if (!(funcp->isMethod() && funcp->isLoose()) && !funcp->dpiImportPrototype()) return; // Already declared manually @@ -58,7 +60,7 @@ class EmitCLazyDecls final : public VNVisitor { } void lazyDeclareConstPoolVar(AstVar* varp) { - if (varp->user2SetOnce()) return; // Already declared + if (!declaredOnce(varp)) return; // Already declared const string nameProtect = m_emitter.topClassName() + "__ConstPool__" + varp->nameProtect(); m_emitter.puts("extern const "); @@ -68,17 +70,17 @@ class EmitCLazyDecls final : public VNVisitor { } // VISITORS - virtual void visit(AstNodeCCall* nodep) override { + void visit(AstNodeCCall* nodep) override { lazyDeclare(nodep->funcp()); iterateChildren(nodep); } - virtual void visit(AstAddrOfCFunc* nodep) override { + void visit(AstAddrOfCFunc* nodep) override { lazyDeclare(nodep->funcp()); iterateChildren(nodep); } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { AstVar* const varp = nodep->varp(); // Only constant pool symbols are lazy declared for now ... if (EmitCBaseVisitor::isConstPoolMod(EmitCParentModule::get(varp))) { @@ -86,9 +88,7 @@ class EmitCLazyDecls final : public VNVisitor { } } - virtual void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } - - VL_DEBUG_FUNC; + void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } public: explicit EmitCLazyDecls(EmitCBaseVisitor& emitter) @@ -106,8 +106,8 @@ public: m_emitter.puts(suffix); m_emitter.ensureNewLine(); } - void declared(AstCFunc* nodep) { nodep->user2SetOnce(); } - void reset() { AstNode::user2ClearTree(); } + void declared(AstCFunc* nodep) { m_emitted.insert(nodep); } + void reset() { m_emitted.clear(); } }; //###################################################################### @@ -152,7 +152,6 @@ protected: public: // METHODS - VL_DEBUG_FUNC; // Declare debug() // ACCESSORS void splitSizeInc(int count) { m_splitSize += count; } @@ -211,7 +210,7 @@ public: // VISITORS using EmitCConstInit::visit; - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { VL_RESTORER(m_useSelfForThis); VL_RESTORER(m_cfuncp); m_cfuncp = nodep; @@ -279,12 +278,12 @@ public: if (nodep->ifdef() != "") puts("#endif // " + nodep->ifdef() + "\n"); } - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { UASSERT_OBJ(m_cfuncp, nodep, "Cannot emit non-local variable"); emitVarDecl(nodep); } - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { bool paren = true; bool decind = false; bool rhs = true; @@ -366,8 +365,8 @@ public: if (decind) ofp()->blockDec(); puts(";\n"); } - virtual void visit(AstAlwaysPublic*) override {} - virtual void visit(AstAssocSel* nodep) override { + void visit(AstAlwaysPublic*) override {} + void visit(AstAssocSel* nodep) override { iterateAndNextNull(nodep->fromp()); putbs(".at("); AstAssocArrayDType* const adtypep = VN_AS(nodep->fromp()->dtypep(), AssocArrayDType); @@ -379,7 +378,7 @@ public: } puts(")"); } - virtual void visit(AstWildcardSel* nodep) override { + void visit(AstWildcardSel* nodep) override { iterateAndNextNull(nodep->fromp()); putbs(".at("); AstWildcardArrayDType* const adtypep = VN_AS(nodep->fromp()->dtypep(), WildcardArrayDType); @@ -387,7 +386,7 @@ public: iterateAndNextNull(nodep->bitp()); puts(")"); } - virtual void visit(AstCCall* nodep) override { + void visit(AstCCall* nodep) override { const AstCFunc* const funcp = nodep->funcp(); const AstNodeModule* const funcModp = EmitCParentModule::get(funcp); if (funcp->dpiImportPrototype()) { @@ -413,7 +412,7 @@ public: } emitCCallArgs(nodep, nodep->selfPointerProtect(m_useSelfForThis)); } - virtual void visit(AstCMethodCall* nodep) override { + void visit(AstCMethodCall* nodep) override { const AstCFunc* const funcp = nodep->funcp(); UASSERT_OBJ(!funcp->isLoose(), nodep, "Loose method called via AstCMethodCall"); iterate(nodep->fromp()); @@ -421,7 +420,7 @@ public: puts(funcp->nameProtect()); emitCCallArgs(nodep, ""); } - virtual void visit(AstCNew* nodep) override { + void visit(AstCNew* nodep) override { bool comma = false; puts("std::make_shared<" + prefixNameProtect(nodep->dtypep()) + ">("); puts("vlSymsp"); // TODO make this part of argsp, and eliminate when unnecessary @@ -433,7 +432,7 @@ public: } puts(")"); } - virtual void visit(AstCMethodHard* nodep) override { + void visit(AstCMethodHard* nodep) override { iterate(nodep->fromp()); puts("."); puts(nodep->name()); @@ -455,8 +454,8 @@ public: UASSERT_OBJ(!nodep->isStatement() || VN_IS(nodep->dtypep(), VoidDType), nodep, "Statement of non-void data type"); } - virtual void visit(AstLambdaArgRef* nodep) override { putbs(nodep->nameProtect()); } - virtual void visit(AstWith* nodep) override { + void visit(AstLambdaArgRef* nodep) override { putbs(nodep->nameProtect()); } + void visit(AstWith* nodep) override { // With uses a C++11 lambda putbs("[=]("); if (auto* const argrefp = nodep->indexArgRefp()) { @@ -471,11 +470,11 @@ public: iterateAndNextNull(nodep->exprp()); puts("; }\n"); } - virtual void visit(AstNodeCase* nodep) override { // LCOV_EXCL_LINE + void visit(AstNodeCase* nodep) override { // LCOV_EXCL_LINE // In V3Case... nodep->v3fatalSrc("Case statements should have been reduced out"); } - virtual void visit(AstComment* nodep) override { + void visit(AstComment* nodep) override { string at; if (nodep->showAt()) { at = " at " + nodep->fileline()->ascii(); @@ -487,7 +486,7 @@ public: } iterateChildren(nodep); } - virtual void visit(AstCoverDecl* nodep) override { + void visit(AstCoverDecl* nodep) override { puts("vlSelf->__vlCoverInsert("); // As Declared in emitCoverageDecl puts("&(vlSymsp->__Vcoverage["); puts(cvtToStr(nodep->dataDeclThisp()->binNum())); @@ -515,7 +514,7 @@ public: putsQuoted(nodep->linescov()); puts(");\n"); } - virtual void visit(AstCoverInc* nodep) override { + void visit(AstCoverInc* nodep) override { if (v3Global.opt.threads()) { puts("vlSymsp->__Vcoverage["); puts(cvtToStr(nodep->declp()->dataDeclThisp()->binNum())); @@ -526,17 +525,17 @@ public: puts("]);\n"); } } - virtual void visit(AstCReturn* nodep) override { + void visit(AstCReturn* nodep) override { puts("return ("); iterateAndNextNull(nodep->lhsp()); puts(");\n"); } - virtual void visit(AstDisplay* nodep) override { + void visit(AstDisplay* nodep) override { string text = nodep->fmtp()->text(); if (nodep->addNewline()) text += "\n"; displayNode(nodep, nodep->fmtp()->scopeNamep(), text, nodep->fmtp()->exprsp(), false); } - virtual void visit(AstDumpCtl* nodep) override { + void visit(AstDumpCtl* nodep) override { switch (nodep->ctlType()) { case VDumpCtlType::FILE: puts("vlSymsp->_vm_contextp__->dumpfile("); @@ -575,7 +574,7 @@ public: default: nodep->v3fatalSrc("Bad case, unexpected " << nodep->ctlType().ascii()); } } - virtual void visit(AstScopeName* nodep) override { + void visit(AstScopeName* nodep) override { // For use under AstCCalls for dpiImports. ScopeNames under // displays are handled in AstDisplay if (!nodep->dpiExport()) { @@ -584,20 +583,20 @@ public: putbs("(&(vlSymsp->" + protect("__Vscope_" + scope) + "))"); } } - virtual void visit(AstSFormat* nodep) override { + void visit(AstSFormat* nodep) override { displayNode(nodep, nodep->fmtp()->scopeNamep(), nodep->fmtp()->text(), nodep->fmtp()->exprsp(), false); } - virtual void visit(AstSFormatF* nodep) override { + void visit(AstSFormatF* nodep) override { displayNode(nodep, nodep->scopeNamep(), nodep->text(), nodep->exprsp(), false); } - virtual void visit(AstFScanF* nodep) override { + void visit(AstFScanF* nodep) override { displayNode(nodep, nullptr, nodep->text(), nodep->exprsp(), true); } - virtual void visit(AstSScanF* nodep) override { + void visit(AstSScanF* nodep) override { displayNode(nodep, nullptr, nodep->text(), nodep->exprsp(), true); } - virtual void visit(AstValuePlusArgs* nodep) override { + void visit(AstValuePlusArgs* nodep) override { puts("VL_VALUEPLUSARGS_IN"); emitIQW(nodep->outp()); puts("("); @@ -609,19 +608,19 @@ public: iterateAndNextNull(nodep->outp()); puts(")"); } - virtual void visit(AstTestPlusArgs* nodep) override { + void visit(AstTestPlusArgs* nodep) override { puts("VL_TESTPLUSARGS_I("); emitCvtPackStr(nodep->searchp()); puts(")"); } - virtual void visit(AstFError* nodep) override { + void visit(AstFError* nodep) override { puts("VL_FERROR_IN("); iterateAndNextNull(nodep->filep()); putbs(", "); iterateAndNextNull(nodep->strp()); puts(")"); } - virtual void visit(AstFGetS* nodep) override { + void visit(AstFGetS* nodep) override { checkMaxWords(nodep); emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nullptr); } @@ -634,7 +633,7 @@ public: << " bits exceeds hardcoded limit VL_VALUE_STRING_MAX_WORDS in verilatedos.h"); } } - virtual void visit(AstFOpen* nodep) override { + void visit(AstFOpen* nodep) override { iterateAndNextNull(nodep->filep()); puts(" = VL_FOPEN_NN("); emitCvtPackStr(nodep->filenamep()); @@ -644,13 +643,13 @@ public: emitCvtPackStr(nodep->modep()); puts(");\n"); } - virtual void visit(AstFOpenMcd* nodep) override { + void visit(AstFOpenMcd* nodep) override { iterateAndNextNull(nodep->filep()); puts(" = VL_FOPEN_MCD_N("); emitCvtPackStr(nodep->filenamep()); puts(");\n"); } - virtual void visit(AstNodeReadWriteMem* nodep) override { + void visit(AstNodeReadWriteMem* nodep) override { puts(nodep->cFuncPrefixp()); puts("N("); puts(nodep->isHex() ? "true" : "false"); @@ -699,14 +698,14 @@ public: } puts(");\n"); } - virtual void visit(AstFClose* nodep) override { + void visit(AstFClose* nodep) override { puts("VL_FCLOSE_I("); iterateAndNextNull(nodep->filep()); puts("); "); iterateAndNextNull(nodep->filep()); // For safety, so user doesn't later WRITE with it. puts(" = 0;\n"); } - virtual void visit(AstFFlush* nodep) override { + void visit(AstFFlush* nodep) override { if (!nodep->filep()) { puts("Verilated::runFlushCallbacks();\n"); } else { @@ -717,7 +716,7 @@ public: puts("); }\n"); } } - virtual void visit(AstFSeek* nodep) override { + void visit(AstFSeek* nodep) override { puts("(VL_FSEEK_I("); iterateAndNextNull(nodep->filep()); puts(","); @@ -726,17 +725,17 @@ public: iterateAndNextNull(nodep->operation()); puts(") == -1 ? -1 : 0)"); } - virtual void visit(AstFTell* nodep) override { + void visit(AstFTell* nodep) override { puts("VL_FTELL_I("); iterateAndNextNull(nodep->filep()); puts(")"); } - virtual void visit(AstFRewind* nodep) override { + void visit(AstFRewind* nodep) override { puts("(VL_FSEEK_I("); iterateAndNextNull(nodep->filep()); puts(", 0, 0) == -1 ? -1 : 0)"); } - virtual void visit(AstFRead* nodep) override { + void visit(AstFRead* nodep) override { puts("VL_FREAD_I("); puts(cvtToStr(nodep->memp()->widthMin())); // Need real storage width putbs(","); @@ -779,12 +778,12 @@ public: } puts(")"); } - virtual void visit(AstSysFuncAsTask* nodep) override { + void visit(AstSysFuncAsTask* nodep) override { if (!nodep->lhsp()->isWide()) puts("(void)"); iterateAndNextNull(nodep->lhsp()); if (!nodep->lhsp()->isWide()) puts(";"); } - virtual void visit(AstSystemT* nodep) override { + void visit(AstSystemT* nodep) override { puts("(void)VL_SYSTEM_I"); emitIQW(nodep->lhsp()); puts("("); @@ -796,7 +795,7 @@ public: iterateAndNextNull(nodep->lhsp()); puts(");\n"); } - virtual void visit(AstSystemF* nodep) override { + void visit(AstSystemF* nodep) override { puts("VL_SYSTEM_I"); emitIQW(nodep->lhsp()); puts("("); @@ -808,30 +807,30 @@ public: iterateAndNextNull(nodep->lhsp()); puts(")"); } - virtual void visit(AstJumpBlock* nodep) override { + void visit(AstJumpBlock* nodep) override { nodep->labelNum(++m_labelNum); puts("{\n"); // Make it visually obvious label jumps outside these iterateAndNextNull(nodep->stmtsp()); iterateAndNextNull(nodep->endStmtsp()); puts("}\n"); } - virtual void visit(AstJumpGo* nodep) override { + void visit(AstJumpGo* nodep) override { puts("goto __Vlabel" + cvtToStr(nodep->labelp()->blockp()->labelNum()) + ";\n"); } - virtual void visit(AstJumpLabel* nodep) override { + void visit(AstJumpLabel* nodep) override { puts("__Vlabel" + cvtToStr(nodep->blockp()->labelNum()) + ": ;\n"); } - virtual void visit(AstWhile* nodep) override { + void visit(AstWhile* nodep) override { iterateAndNextNull(nodep->precondsp()); puts("while ("); iterateAndNextNull(nodep->condp()); puts(") {\n"); - iterateAndNextNull(nodep->bodysp()); + iterateAndNextNull(nodep->stmtsp()); iterateAndNextNull(nodep->incsp()); iterateAndNextNull(nodep->precondsp()); // Need to recompute before next loop puts("}\n"); } - virtual void visit(AstNodeIf* nodep) override { + void visit(AstNodeIf* nodep) override { puts("if ("); if (!nodep->branchPred().unknown()) { puts(nodep->branchPred().ascii()); @@ -840,7 +839,7 @@ public: iterateAndNextNull(nodep->condp()); if (!nodep->branchPred().unknown()) puts(")"); puts(") {\n"); - iterateAndNextNull(nodep->ifsp()); + iterateAndNextNull(nodep->thensp()); puts("}"); if (!nodep->elsesp()) { puts("\n"); @@ -855,7 +854,7 @@ public: } } } - virtual void visit(AstExprStmt* nodep) override { + void visit(AstExprStmt* nodep) override { // GCC allows compound statements in expressions, but this is not standard. // So we use an immediate-evaluation lambda and comma operator putbs("([&]() {\n"); @@ -864,7 +863,7 @@ public: iterateAndNextNull(nodep->resultp()); puts(")"); } - virtual void visit(AstStop* nodep) override { + void visit(AstStop* nodep) override { puts("VL_STOP_MT("); putsQuoted(protect(nodep->fileline()->filename())); puts(", "); @@ -872,38 +871,38 @@ public: puts(", \"\""); puts(");\n"); } - virtual void visit(AstFinish* nodep) override { + void visit(AstFinish* nodep) override { puts("VL_FINISH_MT("); putsQuoted(protect(nodep->fileline()->filename())); puts(", "); puts(cvtToStr(nodep->fileline()->lineno())); puts(", \"\");\n"); } - virtual void visit(AstPrintTimeScale* nodep) override { + void visit(AstPrintTimeScale* nodep) override { puts("VL_PRINTTIMESCALE("); putsQuoted(protect(nodep->name())); puts(", "); putsQuoted(nodep->timeunit().ascii()); puts(", vlSymsp->_vm_contextp__);\n"); } - virtual void visit(AstRand* nodep) override { + void visit(AstRand* nodep) override { emitOpName(nodep, nodep->emitC(), nodep->seedp(), nullptr, nullptr); } - virtual void visit(AstTime* nodep) override { + void visit(AstTime* nodep) override { puts("VL_TIME_UNITED_Q("); if (nodep->timeunit().isNone()) nodep->v3fatalSrc("$time has no units"); puts(cvtToStr(nodep->timeunit().multiplier() / v3Global.rootp()->timeprecision().multiplier())); puts(")"); } - virtual void visit(AstTimeD* nodep) override { + void visit(AstTimeD* nodep) override { puts("VL_TIME_UNITED_D("); if (nodep->timeunit().isNone()) nodep->v3fatalSrc("$realtime has no units"); puts(cvtToStr(nodep->timeunit().multiplier() / v3Global.rootp()->timeprecision().multiplier())); puts(")"); } - virtual void visit(AstTimeFormat* nodep) override { + void visit(AstTimeFormat* nodep) override { puts("VL_TIMEFORMAT_IINI("); iterateAndNextNull(nodep->unitsp()); puts(", "); @@ -914,7 +913,7 @@ public: iterateAndNextNull(nodep->widthp()); puts(", vlSymsp->_vm_contextp__);\n"); } - virtual void visit(AstNodeSimpleText* nodep) override { + void visit(AstNodeSimpleText* nodep) override { const string text = m_inUC && m_useSelfForThis ? VString::replaceWord(nodep->text(), "this", "vlSelf") : nodep->text(); @@ -924,42 +923,42 @@ public: ofp()->putsNoTracking(text); } } - virtual void visit(AstTextBlock* nodep) override { + void visit(AstTextBlock* nodep) override { visit(static_cast(nodep)); for (AstNode* childp = nodep->nodesp(); childp; childp = childp->nextp()) { iterate(childp); if (nodep->commas() && childp->nextp()) puts(", "); } } - virtual void visit(AstCStmt* nodep) override { + void visit(AstCStmt* nodep) override { putbs(""); - iterateAndNextNull(nodep->bodysp()); + iterateAndNextNull(nodep->exprsp()); } - virtual void visit(AstCMath* nodep) override { + void visit(AstCMath* nodep) override { putbs(""); - iterateAndNextNull(nodep->bodysp()); + iterateAndNextNull(nodep->exprsp()); } - virtual void visit(AstUCStmt* nodep) override { + void visit(AstUCStmt* nodep) override { VL_RESTORER(m_inUC); m_inUC = true; putsDecoration(ifNoProtect("// $c statement at " + nodep->fileline()->ascii() + "\n")); - iterateAndNextNull(nodep->bodysp()); + iterateAndNextNull(nodep->exprsp()); puts("\n"); } - virtual void visit(AstUCFunc* nodep) override { + void visit(AstUCFunc* nodep) override { VL_RESTORER(m_inUC); m_inUC = true; puts("\n"); putsDecoration(ifNoProtect("// $c function at " + nodep->fileline()->ascii() + "\n")); - iterateAndNextNull(nodep->bodysp()); + iterateAndNextNull(nodep->exprsp()); puts("\n"); } // Operators - virtual void visit(AstNodeTermop* nodep) override { + void visit(AstNodeTermop* nodep) override { emitOpName(nodep, nodep->emitC(), nullptr, nullptr, nullptr); } - virtual void visit(AstNodeUniop* nodep) override { + void visit(AstNodeUniop* nodep) override { if (nodep->emitCheckMaxWords() && (nodep->widthWords() > VL_MULS_MAX_WORDS || nodep->lhsp()->widthWords() > VL_MULS_MAX_WORDS)) { @@ -979,7 +978,7 @@ public: emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nullptr, nullptr); } } - virtual void visit(AstNodeBiop* nodep) override { + void visit(AstNodeBiop* nodep) override { if (nodep->emitCheckMaxWords() && nodep->widthWords() > VL_MULS_MAX_WORDS) { nodep->v3warn( E_UNSUPPORTED, @@ -999,11 +998,11 @@ public: emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nullptr); } } - virtual void visit(AstNodeTriop* nodep) override { + void visit(AstNodeTriop* nodep) override { UASSERT_OBJ(!emitSimpleOk(nodep), nodep, "Triop cannot be described in a simple way"); emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nodep->thsp()); } - virtual void visit(AstRedXor* nodep) override { + void visit(AstRedXor* nodep) override { if (nodep->lhsp()->isWide()) { visit(static_cast(nodep)); } else { @@ -1019,7 +1018,7 @@ public: puts(")"); } } - virtual void visit(AstCCast* nodep) override { + void visit(AstCCast* nodep) override { // Extending a value of the same word width is just a NOP. if (nodep->size() <= VL_IDATASIZE) { puts("(IData)("); @@ -1029,26 +1028,26 @@ public: iterateAndNextNull(nodep->lhsp()); puts(")"); } - virtual void visit(AstNodeCond* nodep) override { + void visit(AstNodeCond* nodep) override { // Widths match up already, so we'll just use C++'s operator w/o any temps. - if (nodep->expr1p()->isWide()) { - emitOpName(nodep, nodep->emitC(), nodep->condp(), nodep->expr1p(), nodep->expr2p()); + if (nodep->thenp()->isWide()) { + emitOpName(nodep, nodep->emitC(), nodep->condp(), nodep->thenp(), nodep->elsep()); } else { putbs("("); iterateAndNextNull(nodep->condp()); putbs(" ? "); - iterateAndNextNull(nodep->expr1p()); + iterateAndNextNull(nodep->thenp()); putbs(" : "); - iterateAndNextNull(nodep->expr2p()); + iterateAndNextNull(nodep->elsep()); puts(")"); } } - virtual void visit(AstMemberSel* nodep) override { + void visit(AstMemberSel* nodep) override { iterateAndNextNull(nodep->fromp()); putbs("->"); puts(nodep->varp()->nameProtect()); } - virtual void visit(AstNullCheck* nodep) override { + void visit(AstNullCheck* nodep) override { puts("VL_NULL_CHECK("); iterateAndNextNull(nodep->lhsp()); puts(", "); @@ -1057,17 +1056,17 @@ public: puts(cvtToStr(nodep->fileline()->lineno())); puts(")"); } - virtual void visit(AstNewCopy* nodep) override { + void visit(AstNewCopy* nodep) override { puts("std::make_shared<" + prefixNameProtect(nodep->dtypep()) + ">("); puts("*"); // i.e. make into a reference iterateAndNextNull(nodep->rhsp()); puts(")"); } - virtual void visit(AstSel* nodep) override { + void visit(AstSel* nodep) override { // Note ASSIGN checks for this on a LHS emitOpName(nodep, nodep->emitC(), nodep->fromp(), nodep->lsbp(), nodep->thsp()); } - virtual void visit(AstReplicate* nodep) override { + void visit(AstReplicate* nodep) override { if (nodep->lhsp()->widthMin() == 1 && !nodep->isWide()) { UASSERT_OBJ((static_cast(VN_AS(nodep->rhsp(), Const)->toUInt()) * nodep->lhsp()->widthMin()) @@ -1086,7 +1085,7 @@ public: emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nullptr); } } - virtual void visit(AstStreamL* nodep) override { + void visit(AstStreamL* nodep) override { // Attempt to use a "fast" stream function for slice size = power of 2 if (!nodep->isWide()) { const uint32_t isPow2 = VN_AS(nodep->rhsp(), Const)->num().countOnes() == 1; @@ -1108,14 +1107,14 @@ public: emitOpName(nodep, "VL_STREAML_%nq%lq%rq(%lw, %P, %li, %ri)", nodep->lhsp(), nodep->rhsp(), nullptr); } - virtual void visit(AstCastDynamic* nodep) override { + void visit(AstCastDynamic* nodep) override { putbs("VL_CAST_DYNAMIC("); iterateAndNextNull(nodep->lhsp()); puts(", "); iterateAndNextNull(nodep->rhsp()); puts(")"); } - virtual void visit(AstCountBits* nodep) override { + void visit(AstCountBits* nodep) override { putbs("VL_COUNTBITS_"); emitIQW(nodep->lhsp()); puts("("); @@ -1135,9 +1134,9 @@ public: iterateAndNextNull(nodep->fhsp()); puts(")"); } - virtual void visit(AstInitItem* nodep) override { iterateChildren(nodep); } + void visit(AstInitItem* nodep) override { iterateChildren(nodep); } // Terminals - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { const AstVar* const varp = nodep->varp(); const AstNodeModule* const varModp = EmitCParentModule::get(varp); if (isConstPoolMod(varModp)) { @@ -1154,14 +1153,14 @@ public: } puts(nodep->varp()->nameProtect()); } - virtual void visit(AstAddrOfCFunc* nodep) override { + void visit(AstAddrOfCFunc* nodep) override { // Note: Can be thought to handle more, but this is all that is needed right now const AstCFunc* const funcp = nodep->funcp(); UASSERT_OBJ(funcp->isLoose(), nodep, "Cannot take address of non-loose method"); puts("&"); puts(funcNameProtect(funcp)); } - virtual void visit(AstConst* nodep) override { + void visit(AstConst* nodep) override { if (m_emitConstInit) { EmitCConstInit::visit(nodep); } else if (nodep->isWide()) { @@ -1174,12 +1173,12 @@ public: } // - virtual void visit(AstMTaskBody* nodep) override { + void visit(AstMTaskBody* nodep) override { VL_RESTORER(m_useSelfForThis); m_useSelfForThis = true; iterateChildrenConst(nodep); } - virtual void visit(AstConsAssoc* nodep) override { + void visit(AstConsAssoc* nodep) override { putbs(nodep->dtypep()->cType("", false, false)); puts("()"); if (nodep->defaultp()) { @@ -1188,7 +1187,7 @@ public: puts(")"); } } - virtual void visit(AstSetAssoc* nodep) override { + void visit(AstSetAssoc* nodep) override { iterateAndNextNull(nodep->lhsp()); putbs(".set("); iterateAndNextNull(nodep->keyp()); @@ -1197,7 +1196,7 @@ public: iterateAndNextNull(nodep->valuep()); puts(")"); } - virtual void visit(AstConsWildcard* nodep) override { + void visit(AstConsWildcard* nodep) override { putbs(nodep->dtypep()->cType("", false, false)); puts("()"); if (nodep->defaultp()) { @@ -1206,7 +1205,7 @@ public: puts(")"); } } - virtual void visit(AstSetWildcard* nodep) override { + void visit(AstSetWildcard* nodep) override { iterateAndNextNull(nodep->lhsp()); putbs(".set("); iterateAndNextNull(nodep->keyp()); @@ -1215,7 +1214,7 @@ public: iterateAndNextNull(nodep->valuep()); puts(")"); } - virtual void visit(AstConsDynArray* nodep) override { + void visit(AstConsDynArray* nodep) override { putbs(nodep->dtypep()->cType("", false, false)); if (!nodep->lhsp()) { puts("()"); @@ -1230,7 +1229,7 @@ public: puts(")"); } } - virtual void visit(AstConsQueue* nodep) override { + void visit(AstConsQueue* nodep) override { putbs(nodep->dtypep()->cType("", false, false)); if (!nodep->lhsp()) { puts("()"); @@ -1245,22 +1244,22 @@ public: puts(")"); } } - virtual void visit(AstCReset* nodep) override { + void visit(AstCReset* nodep) override { AstVar* const varp = nodep->varrefp()->varp(); emitVarReset(varp); } - virtual void visit(AstExecGraph* nodep) override { + void visit(AstExecGraph* nodep) override { // The location of the AstExecGraph within the containing AstCFunc is where we want to // invoke the graph and wait for it to complete. Emitting the children does just that. UASSERT_OBJ(!nodep->mTaskBodiesp(), nodep, "These should have been lowered"); iterateChildrenConst(nodep); } - virtual void visit(AstChangeDet* nodep) override { // + void visit(AstChangeDet* nodep) override { // m_blkChangeDetVec.push_back(nodep); } // Default - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { puts(string("\n???? // ") + nodep->prettyTypeName() + "\n"); iterateChildren(nodep); // LCOV_EXCL_START @@ -1278,7 +1277,7 @@ public: m_trackText = trackText; iterate(nodep); } - virtual ~EmitCFunc() override = default; + ~EmitCFunc() override = default; }; #endif // guard diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp index a32f261d0..6e1a541db 100644 --- a/src/V3EmitCHeaders.cpp +++ b/src/V3EmitCHeaders.cpp @@ -24,12 +24,13 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Internal EmitC implementation class EmitCHeader final : public EmitCConstInit { // METHODS - VL_DEBUG_FUNC; // Declare debug() void decorateFirst(bool& first, const string& str) { if (first) { @@ -326,7 +327,7 @@ class EmitCHeader final : public EmitCConstInit { // Close output file VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); } - virtual ~EmitCHeader() override = default; + ~EmitCHeader() override = default; public: static void main(const AstNodeModule* modp) { EmitCHeader emitCHeader(modp); } diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index 9bea7b2c0..c01594c13 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -28,6 +28,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Visitor that gathers the headers required by an AstCFunc @@ -68,59 +70,59 @@ class EmitCGatherDependencies final : VNVisitor { } // VISITORS - virtual void visit(AstCCall* nodep) override { + void visit(AstCCall* nodep) override { addSelfDependency(nodep->selfPointer(), nodep->funcp()); iterateChildrenConst(nodep); } - virtual void visit(AstCNew* nodep) override { + void visit(AstCNew* nodep) override { addDTypeDependency(nodep->dtypep()); iterateChildrenConst(nodep); } - virtual void visit(AstCMethodCall* nodep) override { + void visit(AstCMethodCall* nodep) override { addDTypeDependency(nodep->fromp()->dtypep()); iterateChildrenConst(nodep); } - virtual void visit(AstNewCopy* nodep) override { + void visit(AstNewCopy* nodep) override { addDTypeDependency(nodep->dtypep()); iterateChildrenConst(nodep); } - virtual void visit(AstMemberSel* nodep) override { + void visit(AstMemberSel* nodep) override { addDTypeDependency(nodep->fromp()->dtypep()); iterateChildrenConst(nodep); } - virtual void visit(AstNodeVarRef* nodep) override { + void visit(AstNodeVarRef* nodep) override { addSelfDependency(nodep->selfPointer(), nodep->varp()); iterateChildrenConst(nodep); } - virtual void visit(AstCoverDecl* nodep) override { + void visit(AstCoverDecl* nodep) override { addSymsDependency(); iterateChildrenConst(nodep); } - virtual void visit(AstCoverInc* nodep) override { + void visit(AstCoverInc* nodep) override { addSymsDependency(); iterateChildrenConst(nodep); } - virtual void visit(AstDumpCtl* nodep) override { + void visit(AstDumpCtl* nodep) override { addSymsDependency(); iterateChildrenConst(nodep); } - virtual void visit(AstScopeName* nodep) override { + void visit(AstScopeName* nodep) override { addSymsDependency(); iterateChildrenConst(nodep); } - virtual void visit(AstPrintTimeScale* nodep) override { + void visit(AstPrintTimeScale* nodep) override { addSymsDependency(); iterateChildrenConst(nodep); } - virtual void visit(AstTimeFormat* nodep) override { + void visit(AstTimeFormat* nodep) override { addSymsDependency(); iterateChildrenConst(nodep); } - virtual void visit(AstNodeSimpleText* nodep) override { + void visit(AstNodeSimpleText* nodep) override { if (nodep->text().find("vlSymsp") != string::npos) addSymsDependency(); iterateChildrenConst(nodep); } - virtual void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } + void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } // CONSTRUCTOR explicit EmitCGatherDependencies(AstCFunc* cfuncp) { @@ -148,6 +150,7 @@ class EmitCImp final : EmitCFunc { const std::set* m_requiredHeadersp; // Header files required by output file std::string m_subFileName; // substring added to output filenames V3UniqueNames m_uniqueNames; // For generating unique file names + std::deque& m_cfilesr; // cfiles generated by this emit // METHODS void openNextOutputFile(const std::set& headers, const string& subFileName) { @@ -160,7 +163,8 @@ class EmitCImp final : EmitCFunc { // Unfortunately we have some lint checks here, so we can't just skip processing. // We should move them to a different stage. const string filename = VL_DEV_NULL; - newCFile(filename, /* slow: */ m_slow, /* source: */ true); + m_cfilesr.push_back( + newCFile(filename, /* slow: */ m_slow, /* source: */ true, /* add */ false)); m_ofp = new V3OutCFile(filename); } else { string filename = v3Global.opt.makeDir() + "/" + prefixNameProtect(m_fileModp); @@ -170,7 +174,8 @@ class EmitCImp final : EmitCFunc { } if (m_slow) filename += "__Slow"; filename += ".cpp"; - newCFile(filename, /* slow: */ m_slow, /* source: */ true); + m_cfilesr.push_back( + newCFile(filename, /* slow: */ m_slow, /* source: */ true, /* add */ false)); m_ofp = v3Global.opt.systemC() ? new V3OutScFile(filename) : new V3OutCFile(filename); } @@ -509,7 +514,7 @@ class EmitCImp final : EmitCFunc { } // VISITORS - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { if (splitNeeded()) { // Splitting file, so using parallel build. v3Global.useParallelBuild(true); @@ -522,9 +527,10 @@ class EmitCImp final : EmitCFunc { EmitCFunc::visit(nodep); } - explicit EmitCImp(const AstNodeModule* modp, bool slow) + explicit EmitCImp(const AstNodeModule* modp, bool slow, std::deque& cfilesr) : m_fileModp{modp} - , m_slow{slow} { + , m_slow{slow} + , m_cfilesr{cfilesr} { UINFO(5, " Emitting implementation of " << prefixNameProtect(modp) << endl); m_modp = modp; @@ -540,10 +546,12 @@ class EmitCImp final : EmitCFunc { // Emit implementations of all AstCFunc emitCFuncImp(modp); } - virtual ~EmitCImp() override = default; + ~EmitCImp() override = default; public: - static void main(const AstNodeModule* modp, bool slow) { EmitCImp{modp, slow}; } + static void main(const AstNodeModule* modp, bool slow, std::deque& cfilesr) { + EmitCImp{modp, slow, cfilesr}; + } }; //###################################################################### @@ -551,14 +559,14 @@ public: class EmitCTrace final : EmitCFunc { // NODE STATE/TYPES - // Cleared on netlist - // AstNode::user1() -> int. Enum number - const VNUser1InUse m_inuser1; + // None allowed to support threaded emitting // MEMBERS const bool m_slow; // Making slow file int m_enumNum = 0; // Enumeration number (whole netlist) V3UniqueNames m_uniqueNames; // For generating unique file names + std::unordered_map m_enumNumMap; // EnumDType to enumeration number + std::deque& m_cfilesr; // cfiles generated by this emit // METHODS void openNextOutputFile() { @@ -573,8 +581,9 @@ class EmitCTrace final : EmitCFunc { if (m_slow) filename += "__Slow"; filename += ".cpp"; - AstCFile* const cfilep = newCFile(filename, m_slow, true /*source*/); + AstCFile* const cfilep = newCFile(filename, m_slow, true /*source*/, false /*add*/); cfilep->support(true); + m_cfilesr.push_back(cfilep); if (optSystemC()) { m_ofp = new V3OutScFile(filename); @@ -710,10 +719,10 @@ class EmitCTrace final : EmitCFunc { // Skip over refs-to-refs, but stop before final ref so can get data type name // Alternatively back in V3Width we could push enum names from upper typedefs if (AstEnumDType* const enump = VN_CAST(nodep->skipRefToEnump(), EnumDType)) { - int enumNum = enump->user1(); + int enumNum = m_enumNumMap[enump]; if (!enumNum) { enumNum = ++m_enumNum; - enump->user1(enumNum); + m_enumNumMap[enump] = enumNum; int nvals = 0; puts("{\n"); puts("const char* " + protect("__VenumItemNames") + "[]\n"); @@ -816,7 +825,7 @@ class EmitCTrace final : EmitCFunc { // VISITORS using EmitCFunc::visit; // Suppress hidden overloaded virtual function warning - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { if (!nodep->isTrace()) return; if (nodep->slow() != m_slow) return; @@ -831,17 +840,17 @@ class EmitCTrace final : EmitCFunc { EmitCFunc::visit(nodep); } - virtual void visit(AstTracePushNamePrefix* nodep) override { + void visit(AstTracePushNamePrefix* nodep) override { puts("tracep->pushNamePrefix("); putsQuoted(VIdProtect::protectWordsIf(nodep->prefix(), nodep->protect())); puts(");\n"); } - virtual void visit(AstTracePopNamePrefix* nodep) override { // + void visit(AstTracePopNamePrefix* nodep) override { // puts("tracep->popNamePrefix("); puts(cvtToStr(nodep->count())); puts(");\n"); } - virtual void visit(AstTraceDecl* nodep) override { + void visit(AstTraceDecl* nodep) override { const int enumNum = emitTraceDeclDType(nodep->dtypep()); if (nodep->arrayRange().ranged()) { puts("for (int i = 0; i < " + cvtToStr(nodep->arrayRange().elements()) + "; ++i) {\n"); @@ -852,7 +861,7 @@ class EmitCTrace final : EmitCFunc { puts("\n"); } } - virtual void visit(AstTraceInc* nodep) override { + void visit(AstTraceInc* nodep) override { if (nodep->declp()->arrayRange().ranged()) { // It traces faster if we unroll the loop for (int i = 0; i < nodep->declp()->arrayRange().elements(); i++) { @@ -863,8 +872,9 @@ class EmitCTrace final : EmitCFunc { } } - explicit EmitCTrace(AstNodeModule* modp, bool slow) - : m_slow{slow} { + explicit EmitCTrace(AstNodeModule* modp, bool slow, std::deque& cfilesr) + : m_slow{slow} + , m_cfilesr{cfilesr} { m_modp = modp; // Open output file openNextOutputFile(); @@ -875,10 +885,12 @@ class EmitCTrace final : EmitCFunc { // Close output file VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); } - virtual ~EmitCTrace() override = default; + ~EmitCTrace() override = default; public: - static void main(AstNodeModule* modp, bool slow) { EmitCTrace{modp, slow}; } + static void main(AstNodeModule* modp, bool slow, std::deque& cfilesr) { + EmitCTrace{modp, slow, cfilesr}; + } }; //###################################################################### @@ -888,19 +900,27 @@ void V3EmitC::emitcImp() { UINFO(2, __FUNCTION__ << ": " << endl); // Make parent module pointers available. const EmitCParentModule emitCParentModule; + std::list> cfiles; // Process each module in turn for (const AstNode* nodep = v3Global.rootp()->modulesp(); nodep; nodep = nodep->nextp()) { if (VN_IS(nodep, Class)) continue; // Imped with ClassPackage const AstNodeModule* const modp = VN_AS(nodep, NodeModule); - EmitCImp::main(modp, /* slow: */ true); - EmitCImp::main(modp, /* slow: */ false); + cfiles.emplace_back(); + EmitCImp::main(modp, /* slow: */ true, cfiles.back()); + cfiles.emplace_back(); + EmitCImp::main(modp, /* slow: */ false, cfiles.back()); } // Emit trace routines (currently they can only exist in the top module) if (v3Global.opt.trace() && !v3Global.opt.lintOnly()) { - EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ true); - EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ false); + cfiles.emplace_back(); + EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ true, cfiles.back()); + cfiles.emplace_back(); + EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ false, cfiles.back()); + } + for (const auto& collr : cfiles) { + for (const auto cfilep : collr) v3Global.rootp()->addFilesp(cfilep); } } diff --git a/src/V3EmitCInlines.cpp b/src/V3EmitCInlines.cpp index f9a667e25..24556fd5f 100644 --- a/src/V3EmitCInlines.cpp +++ b/src/V3EmitCInlines.cpp @@ -24,6 +24,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### class EmitCInlines final : EmitCBaseVisitor { @@ -32,18 +34,18 @@ class EmitCInlines final : EmitCBaseVisitor { // METHODS // VISITORS - virtual void visit(AstCNew* nodep) override { + void visit(AstCNew* nodep) override { if (v3Global.opt.savable()) v3warn(E_UNSUPPORTED, "Unsupported: --savable with dynamic new"); iterateChildren(nodep); } - virtual void visit(AstDumpCtl* nodep) override { + void visit(AstDumpCtl* nodep) override { if (v3Global.opt.trace()) v3Global.needTraceDumper(true); iterateChildren(nodep); } //--------------------------------------- - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: explicit EmitCInlines(AstNetlist* nodep) { iterate(nodep); } diff --git a/src/V3EmitCMain.cpp b/src/V3EmitCMain.cpp index be04510aa..a4f95f486 100644 --- a/src/V3EmitCMain.cpp +++ b/src/V3EmitCMain.cpp @@ -25,6 +25,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### class EmitCMain final : EmitCBaseVisitor { @@ -32,7 +34,7 @@ class EmitCMain final : EmitCBaseVisitor { // VISITORS // This visitor doesn't really iterate, but exist to appease base class - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } // LCOV_EXCL_LINE + void visit(AstNode* nodep) override { iterateChildren(nodep); } // LCOV_EXCL_LINE public: // CONSTRUCTORS diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp index c053cc45a..d72f6a863 100644 --- a/src/V3EmitCMake.cpp +++ b/src/V3EmitCMake.cpp @@ -26,13 +26,14 @@ #include -//###################################################################### -// Emit statements +VL_DEFINE_DEBUG_FUNCTIONS; + +// ###################################################################### +// Emit statements class CMakeEmitter final { // METHODS - VL_DEBUG_FUNC; // Declare debug() // STATIC FUNCTIONS diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp index 28687c19c..52141a109 100644 --- a/src/V3EmitCModel.cpp +++ b/src/V3EmitCModel.cpp @@ -26,6 +26,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + class EmitCModel final : public EmitCFunc { // TYPES using CFuncVector = std::vector; @@ -34,8 +36,6 @@ class EmitCModel final : public EmitCFunc { V3UniqueNames m_uniqueNames; // For generating unique file names // METHODS - VL_DEBUG_FUNC; - CFuncVector findFuncps(std::function cb) { CFuncVector funcps; for (AstNode* nodep = m_modp->stmtsp(); nodep; nodep = nodep->nextp()) { @@ -190,7 +190,7 @@ class EmitCModel final : public EmitCFunc { + "C* tfp, int levels, int options = 0);\n"); if (optSystemC()) { puts("/// SC tracing; avoid overloaded virtual function lint warning\n"); - puts("virtual void trace(sc_trace_file* tfp) const override { " + puts("void trace(sc_trace_file* tfp) const override { " "::sc_core::sc_module::trace(tfp); }\n"); } } @@ -552,6 +552,11 @@ class EmitCModel final : public EmitCFunc { "elaboration.\");\n"); puts(/**/ "}"); } + puts(/**/ "if (tfp->isOpen()) {\n"); + puts(/****/ "vl_fatal(__FILE__, __LINE__, __FILE__,\"'" + topClassName() + + +"::trace()' shall not be called after '" + v3Global.opt.traceClassBase() + + "C::open()'.\");\n"); + puts(/**/ "}\n"); puts(/**/ "if (false && levels && options) {} // Prevent unused\n"); puts(/**/ "tfp->spTrace()->addModel(this);\n"); puts(/**/ "tfp->spTrace()->addInitCb(&" + protect("trace_init") + ", &(vlSymsp->TOP));\n"); @@ -565,7 +570,7 @@ class EmitCModel final : public EmitCFunc { // Some hackery to locate handle__V for trace_init_task // Considered a pragma on the handle, but that still doesn't help us attach it here string handle = funcp->name(); - const size_t wr_len = strlen("__Vdpiimwrap_"); + const size_t wr_len = std::strlen("__Vdpiimwrap_"); UASSERT_OBJ(handle.substr(0, wr_len) == "__Vdpiimwrap_", funcp, "Strange trace_init_task function name"); handle = "vlSymsp->TOP." + handle.substr(wr_len); diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 5193bd7e6..d826bf692 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -27,6 +27,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Symbol table emitting @@ -211,7 +213,7 @@ class EmitCSyms final : EmitCBaseVisitor { const string::size_type dpos = whole.rfind("__DOT__"); if (dpos != string::npos) { scpName = whole.substr(0, dpos); - varBase = whole.substr(dpos + strlen("__DOT__")); + varBase = whole.substr(dpos + std::strlen("__DOT__")); } else { varBase = whole; } @@ -258,7 +260,7 @@ class EmitCSyms final : EmitCBaseVisitor { } // VISITORS - virtual void visit(AstNetlist* nodep) override { + void visit(AstNetlist* nodep) override { // Collect list of scopes iterateChildren(nodep); varsExpand(); @@ -280,8 +282,8 @@ class EmitCSyms final : EmitCBaseVisitor { if (!m_dpiHdrOnly) emitDpiImp(); } } - virtual void visit(AstConstPool* nodep) override {} // Ignore - virtual void visit(AstNodeModule* nodep) override { + void visit(AstConstPool* nodep) override {} // Ignore + void visit(AstNodeModule* nodep) override { nameCheck(nodep); VL_RESTORER(m_modp); { @@ -289,7 +291,7 @@ class EmitCSyms final : EmitCBaseVisitor { iterateChildren(nodep); } } - virtual void visit(AstCellInline* nodep) override { + void visit(AstCellInline* nodep) override { if (v3Global.opt.vpi()) { const string type = (nodep->origModName() == "__BEGIN__") ? "SCOPE_OTHER" : "SCOPE_MODULE"; @@ -300,7 +302,7 @@ class EmitCSyms final : EmitCBaseVisitor { std::make_pair(name, ScopeData(scopeSymString(name), name_dedot, timeunit, type))); } } - virtual void visit(AstScope* nodep) override { + void visit(AstScope* nodep) override { if (VN_IS(m_modp, Class)) return; // The ClassPackage is what is visible nameCheck(nodep); @@ -315,7 +317,7 @@ class EmitCSyms final : EmitCBaseVisitor { timeunit, type))); } } - virtual void visit(AstScopeName* nodep) override { + void visit(AstScopeName* nodep) override { const string name = nodep->scopeSymName(); // UINFO(9,"scnameins sp "<name()<<" sp "<scopePrettySymName() // <<" ss"<isSigUserRdPublic() && !m_cfuncp) m_modVars.emplace_back(std::make_pair(m_modp, nodep)); } - virtual void visit(AstCoverDecl* nodep) override { + void visit(AstCoverDecl* nodep) override { // Assign numbers to all bins, so we know how big of an array to use if (!nodep->dataDeclNullp()) { // else duplicate we don't need code for nodep->binNum(m_coverBins++); } } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { nameCheck(nodep); if (nodep->dpiImportPrototype() || nodep->dpiExportDispatcher()) m_dpis.push_back(nodep); VL_RESTORER(m_cfuncp); @@ -360,8 +362,8 @@ class EmitCSyms final : EmitCBaseVisitor { } //--------------------------------------- - virtual void visit(AstConst*) override {} - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstConst*) override {} + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: explicit EmitCSyms(AstNetlist* nodep, bool dpiHdrOnly) diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index e4db53ede..c05f02af8 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -24,13 +24,14 @@ #include "V3HierBlock.h" #include "V3Os.h" +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Emit statements and math operators class EmitMk final { public: // METHODS - VL_DEBUG_FUNC; // Declare debug() void putMakeClassEntry(V3OutMkFile& of, const string& name) { of.puts("\t" + V3Os::filenameNonDirExt(name) + " \\\n"); @@ -292,7 +293,7 @@ class EmitMkHierVerilation final { of.puts("# Verilation of hierarchical blocks are executed in this directory\n"); of.puts("VM_HIER_RUN_DIR := " + cwd + "\n"); of.puts("# Common options for hierarchical blocks\n"); - const string fullpath_bin = V3Os::filenameRealPath(v3Global.opt.bin()); + const string fullpath_bin = V3Os::filenameRealPath(v3Global.opt.buildDepBin()); const string verilator_wrapper = V3Os::filenameDir(fullpath_bin) + "/verilator"; of.puts("VM_HIER_VERILATOR := " + verilator_wrapper + "\n"); of.puts("VM_HIER_INPUT_FILES := \\\n"); @@ -399,7 +400,6 @@ public: V3OutMkFile of(m_makefile); emit(of); } - VL_DEBUG_FUNC; // Declare debug() }; //###################################################################### diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 1bd2c3a47..624fc3f19 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -26,6 +26,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Emit statements and math operators @@ -36,7 +38,6 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { AstSenTree* m_sensesp; // Domain for printing one a ALWAYS under a ACTIVE // METHODS - VL_DEBUG_FUNC; // Declare debug() virtual void puts(const string& str) = 0; virtual void putbs(const string& str) = 0; @@ -53,14 +54,14 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { } // VISITORS - virtual void visit(AstNetlist* nodep) override { iterateAndNextConstNull(nodep->modulesp()); } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNetlist* nodep) override { iterateAndNextConstNull(nodep->modulesp()); } + void visit(AstNodeModule* nodep) override { putfs(nodep, nodep->verilogKwd() + " " + prefixNameProtect(nodep) + ";\n"); iterateChildrenConst(nodep); putqs(nodep, "end" + nodep->verilogKwd() + "\n"); } - virtual void visit(AstPort* nodep) override {} - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstPort* nodep) override {} + void visit(AstNodeFTask* nodep) override { putfs(nodep, nodep->isFunction() ? "function" : "task"); puts(" "); puts(nodep->prettyName()); @@ -70,7 +71,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { putfs(nodep, nodep->isFunction() ? "endfunction\n" : "endtask\n"); } - virtual void visit(AstBegin* nodep) override { + void visit(AstBegin* nodep) override { if (nodep->name() == "") { putbs("begin\n"); } else { @@ -79,7 +80,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { iterateChildrenConst(nodep); puts("end\n"); } - virtual void visit(AstFork* nodep) override { + void visit(AstFork* nodep) override { if (nodep->name() == "") { putbs("fork\n"); } else { @@ -89,19 +90,19 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { puts(nodep->joinType().verilogKwd()); puts("\n"); } - virtual void visit(AstFinal* nodep) override { + void visit(AstFinal* nodep) override { putfs(nodep, "final begin\n"); iterateChildrenConst(nodep); putqs(nodep, "end\n"); } - virtual void visit(AstInitial* nodep) override { + void visit(AstInitial* nodep) override { putfs(nodep, "initial begin\n"); iterateChildrenConst(nodep); putqs(nodep, "end\n"); } - virtual void visit(AstInitialAutomatic* nodep) override { iterateChildrenConst(nodep); } - virtual void visit(AstInitialStatic* nodep) override { iterateChildrenConst(nodep); } - virtual void visit(AstAlways* nodep) override { + void visit(AstInitialAutomatic* nodep) override { iterateChildrenConst(nodep); } + void visit(AstInitialStatic* nodep) override { iterateChildrenConst(nodep); } + void visit(AstAlways* nodep) override { putfs(nodep, "always "); if (m_sensesp) { iterateAndNextConstNull(m_sensesp); @@ -110,10 +111,10 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { iterateAndNextConstNull(nodep->sensesp()); } putbs(" begin\n"); - iterateAndNextConstNull(nodep->bodysp()); + iterateAndNextConstNull(nodep->stmtsp()); putqs(nodep, "end\n"); } - virtual void visit(AstAlwaysPublic* nodep) override { + void visit(AstAlwaysPublic* nodep) override { putfs(nodep, "/*verilator public_flat_rw "); if (m_sensesp) { iterateAndNextConstNull(m_sensesp); @@ -122,46 +123,46 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { iterateAndNextConstNull(nodep->sensesp()); } putqs(nodep, " "); - iterateAndNextConstNull(nodep->bodysp()); + iterateAndNextConstNull(nodep->stmtsp()); putqs(nodep, "*/\n"); } - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { if (VN_IS(nodep, AssignForce)) puts("force "); iterateAndNextConstNull(nodep->lhsp()); putfs(nodep, " " + nodep->verilogKwd() + " "); iterateAndNextConstNull(nodep->rhsp()); if (!m_suppressSemi) puts(";\n"); } - virtual void visit(AstAssignDly* nodep) override { + void visit(AstAssignDly* nodep) override { iterateAndNextConstNull(nodep->lhsp()); putfs(nodep, " <= "); iterateAndNextConstNull(nodep->rhsp()); puts(";\n"); } - virtual void visit(AstAssignAlias* nodep) override { + void visit(AstAssignAlias* nodep) override { putbs("alias "); iterateAndNextConstNull(nodep->lhsp()); putfs(nodep, " = "); iterateAndNextConstNull(nodep->rhsp()); if (!m_suppressSemi) puts(";\n"); } - virtual void visit(AstAssignW* nodep) override { + void visit(AstAssignW* nodep) override { putfs(nodep, "assign "); iterateAndNextConstNull(nodep->lhsp()); putbs(" = "); iterateAndNextConstNull(nodep->rhsp()); if (!m_suppressSemi) puts(";\n"); } - virtual void visit(AstRelease* nodep) override { + void visit(AstRelease* nodep) override { puts("release "); iterateAndNextConstNull(nodep->lhsp()); if (!m_suppressSemi) puts(";\n"); } - virtual void visit(AstBreak*) override { + void visit(AstBreak*) override { putbs("break"); if (!m_suppressSemi) puts(";\n"); } - virtual void visit(AstSenTree* nodep) override { + void visit(AstSenTree* nodep) override { // AstSenItem is called for dumping in isolation by V3Order putfs(nodep, "@("); for (AstNode* expp = nodep->sensesp(); expp; expp = expp->nextp()) { @@ -170,13 +171,13 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { } puts(")"); } - virtual void visit(AstSenItem* nodep) override { + void visit(AstSenItem* nodep) override { putfs(nodep, ""); puts(nodep->edgeType().verilogKwd()); if (nodep->sensp()) puts(" "); iterateChildrenConst(nodep); } - virtual void visit(AstNodeCase* nodep) override { + void visit(AstNodeCase* nodep) override { putfs(nodep, ""); if (const AstCase* const casep = VN_CAST(nodep, Case)) { if (casep->priorityPragma()) puts("priority "); @@ -197,27 +198,27 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { iterateAndNextConstNull(nodep->itemsp()); putqs(nodep, "endcase\n"); } - virtual void visit(AstCaseItem* nodep) override { + void visit(AstCaseItem* nodep) override { if (nodep->condsp()) { iterateAndNextConstNull(nodep->condsp()); } else { putbs("default"); } putfs(nodep, ": begin "); - iterateAndNextConstNull(nodep->bodysp()); + iterateAndNextConstNull(nodep->stmtsp()); putqs(nodep, "end\n"); } - virtual void visit(AstComment* nodep) override { + void visit(AstComment* nodep) override { puts(std::string{"// "} + nodep->name() + "\n"); iterateChildrenConst(nodep); } - virtual void visit(AstContinue*) override { + void visit(AstContinue*) override { putbs("continue"); if (!m_suppressSemi) puts(";\n"); } - virtual void visit(AstCoverDecl*) override {} // N/A - virtual void visit(AstCoverInc*) override {} // N/A - virtual void visit(AstCoverToggle*) override {} // N/A + void visit(AstCoverDecl*) override {} // N/A + void visit(AstCoverInc*) override {} // N/A + void visit(AstCoverToggle*) override {} // N/A void visitNodeDisplay(AstNode* nodep, AstNode* fileOrStrgp, const string& text, AstNode* exprsp) { @@ -234,26 +235,26 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { } puts(");\n"); } - virtual void visit(AstDisable* nodep) override { putbs("disable " + nodep->name() + ";\n"); } - virtual void visit(AstDisplay* nodep) override { + void visit(AstDisable* nodep) override { putbs("disable " + nodep->name() + ";\n"); } + void visit(AstDisplay* nodep) override { visitNodeDisplay(nodep, nodep->filep(), nodep->fmtp()->text(), nodep->fmtp()->exprsp()); } - virtual void visit(AstElabDisplay* nodep) override { + void visit(AstElabDisplay* nodep) override { visitNodeDisplay(nodep, nullptr, nodep->fmtp()->text(), nodep->fmtp()->exprsp()); } - virtual void visit(AstFScanF* nodep) override { + void visit(AstFScanF* nodep) override { visitNodeDisplay(nodep, nodep->filep(), nodep->text(), nodep->exprsp()); } - virtual void visit(AstSScanF* nodep) override { + void visit(AstSScanF* nodep) override { visitNodeDisplay(nodep, nodep->fromp(), nodep->text(), nodep->exprsp()); } - virtual void visit(AstSFormat* nodep) override { + void visit(AstSFormat* nodep) override { visitNodeDisplay(nodep, nodep->lhsp(), nodep->fmtp()->text(), nodep->fmtp()->exprsp()); } - virtual void visit(AstSFormatF* nodep) override { + void visit(AstSFormatF* nodep) override { visitNodeDisplay(nodep, nullptr, nodep->text(), nodep->exprsp()); } - virtual void visit(AstFOpen* nodep) override { + void visit(AstFOpen* nodep) override { putfs(nodep, nodep->verilogKwd()); putbs("("); iterateAndNextConstNull(nodep->filenamep()); @@ -261,36 +262,34 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { iterateAndNextConstNull(nodep->modep()); puts(");\n"); } - virtual void visit(AstFOpenMcd* nodep) override { + void visit(AstFOpenMcd* nodep) override { putfs(nodep, nodep->verilogKwd()); putbs("("); iterateAndNextConstNull(nodep->filenamep()); puts(");\n"); } - virtual void visit(AstFClose* nodep) override { + void visit(AstFClose* nodep) override { putfs(nodep, nodep->verilogKwd()); putbs("("); if (nodep->filep()) iterateAndNextConstNull(nodep->filep()); puts(");\n"); } - virtual void visit(AstFFlush* nodep) override { + void visit(AstFFlush* nodep) override { putfs(nodep, nodep->verilogKwd()); putbs("("); if (nodep->filep()) iterateAndNextConstNull(nodep->filep()); puts(");\n"); } - virtual void visit(AstJumpBlock* nodep) override { + void visit(AstJumpBlock* nodep) override { putbs("begin : label" + cvtToStr(nodep->labelNum()) + "\n"); if (nodep->stmtsp()) iterateAndNextConstNull(nodep->stmtsp()); puts("end\n"); } - virtual void visit(AstJumpGo* nodep) override { + void visit(AstJumpGo* nodep) override { putbs("disable label" + cvtToStr(nodep->labelp()->blockp()->labelNum()) + ";\n"); } - virtual void visit(AstJumpLabel* nodep) override { - putbs("// " + cvtToStr(nodep->blockp()) + ":\n"); - } - virtual void visit(AstNodeReadWriteMem* nodep) override { + void visit(AstJumpLabel* nodep) override { putbs("// " + cvtToStr(nodep->blockp()) + ":\n"); } + void visit(AstNodeReadWriteMem* nodep) override { putfs(nodep, nodep->verilogKwd()); putbs("("); if (nodep->filenamep()) iterateAndNextConstNull(nodep->filenamep()); @@ -306,17 +305,17 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { } puts(");\n"); } - virtual void visit(AstSysFuncAsTask* nodep) override { + void visit(AstSysFuncAsTask* nodep) override { iterateAndNextConstNull(nodep->lhsp()); puts(";\n"); } - virtual void visit(AstSysIgnore* nodep) override { + void visit(AstSysIgnore* nodep) override { putfs(nodep, nodep->verilogKwd()); putbs("("); iterateAndNextConstNull(nodep->exprsp()); puts(");\n"); } - virtual void visit(AstNodeFor* nodep) override { + void visit(AstNodeFor* nodep) override { putfs(nodep, "for ("); { VL_RESTORER(m_suppressSemi); @@ -328,27 +327,27 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { iterateAndNextConstNull(nodep->incsp()); } puts(") begin\n"); - iterateAndNextConstNull(nodep->bodysp()); + iterateAndNextConstNull(nodep->stmtsp()); putqs(nodep, "end\n"); } - virtual void visit(AstRepeat* nodep) override { + void visit(AstRepeat* nodep) override { putfs(nodep, "repeat ("); iterateAndNextConstNull(nodep->countp()); puts(") begin\n"); - iterateAndNextConstNull(nodep->bodysp()); + iterateAndNextConstNull(nodep->stmtsp()); putfs(nodep, "end\n"); } - virtual void visit(AstWhile* nodep) override { + void visit(AstWhile* nodep) override { iterateAndNextConstNull(nodep->precondsp()); putfs(nodep, "while ("); iterateAndNextConstNull(nodep->condp()); puts(") begin\n"); - iterateAndNextConstNull(nodep->bodysp()); + iterateAndNextConstNull(nodep->stmtsp()); iterateAndNextConstNull(nodep->incsp()); iterateAndNextConstNull(nodep->precondsp()); // Need to recompute before next loop putfs(nodep, "end\n"); } - virtual void visit(AstNodeIf* nodep) override { + void visit(AstNodeIf* nodep) override { putfs(nodep, ""); if (const AstIf* const ifp = VN_CAST(nodep, If)) { if (ifp->priorityPragma()) puts("priority "); @@ -358,7 +357,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { puts("if ("); iterateAndNextConstNull(nodep->condp()); puts(") begin\n"); - iterateAndNextConstNull(nodep->ifsp()); + iterateAndNextConstNull(nodep->thensp()); if (nodep->elsesp()) { putqs(nodep, "end\n"); putqs(nodep, "else begin\n"); @@ -366,7 +365,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { } putqs(nodep, "end\n"); } - virtual void visit(AstPast* nodep) override { + void visit(AstPast* nodep) override { putfs(nodep, "$past("); iterateAndNextConstNull(nodep->exprp()); if (nodep->ticksp()) { @@ -375,21 +374,21 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { } puts(")"); } - virtual void visit(AstReturn* nodep) override { + void visit(AstReturn* nodep) override { putfs(nodep, "return "); iterateAndNextConstNull(nodep->lhsp()); puts(";\n"); } - virtual void visit(AstStop* nodep) override { putfs(nodep, "$stop;\n"); } - virtual void visit(AstFinish* nodep) override { putfs(nodep, "$finish;\n"); } - virtual void visit(AstNodeSimpleText* nodep) override { + void visit(AstStop* nodep) override { putfs(nodep, "$stop;\n"); } + void visit(AstFinish* nodep) override { putfs(nodep, "$finish;\n"); } + void visit(AstNodeSimpleText* nodep) override { if (nodep->tracking() || m_trackText) { puts(nodep->text()); } else { putsNoTracking(nodep->text()); } } - virtual void visit(AstTextBlock* nodep) override { + void visit(AstTextBlock* nodep) override { visit(static_cast(nodep)); { VL_RESTORER(m_suppressSemi); @@ -400,25 +399,25 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { } } } - virtual void visit(AstScopeName* nodep) override {} - virtual void visit(AstCStmt* nodep) override { + void visit(AstScopeName* nodep) override {} + void visit(AstCStmt* nodep) override { putfs(nodep, "$_CSTMT("); - iterateAndNextConstNull(nodep->bodysp()); + iterateAndNextConstNull(nodep->exprsp()); puts(");\n"); } - virtual void visit(AstCMath* nodep) override { + void visit(AstCMath* nodep) override { putfs(nodep, "$_CMATH("); - iterateAndNextConstNull(nodep->bodysp()); + iterateAndNextConstNull(nodep->exprsp()); puts(");\n"); } - virtual void visit(AstUCStmt* nodep) override { + void visit(AstUCStmt* nodep) override { putfs(nodep, "$c("); - iterateAndNextConstNull(nodep->bodysp()); + iterateAndNextConstNull(nodep->exprsp()); puts(");\n"); } - virtual void visit(AstUCFunc* nodep) override { + void visit(AstUCFunc* nodep) override { putfs(nodep, "$c("); - iterateAndNextConstNull(nodep->bodysp()); + iterateAndNextConstNull(nodep->exprsp()); puts(")"); } @@ -481,25 +480,23 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { } } - virtual void visit(AstNodeTermop* nodep) override { - emitVerilogFormat(nodep, nodep->emitVerilog()); - } - virtual void visit(AstNodeUniop* nodep) override { + void visit(AstNodeTermop* nodep) override { emitVerilogFormat(nodep, nodep->emitVerilog()); } + void visit(AstNodeUniop* nodep) override { emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp()); } - virtual void visit(AstNodeBiop* nodep) override { + void visit(AstNodeBiop* nodep) override { emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp()); } - virtual void visit(AstNodeTriop* nodep) override { + void visit(AstNodeTriop* nodep) override { emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp(), nodep->thsp()); } - virtual void visit(AstMemberSel* nodep) override { + void visit(AstMemberSel* nodep) override { iterate(nodep->fromp()); puts("."); puts(nodep->prettyName()); } - virtual void visit(AstAttrOf* nodep) override { + void visit(AstAttrOf* nodep) override { putfs(nodep, "$_ATTROF("); iterateAndNextConstNull(nodep->fromp()); if (nodep->dimp()) { @@ -508,7 +505,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { } puts(")"); } - virtual void visit(AstInitArray* nodep) override { + void visit(AstInitArray* nodep) override { putfs(nodep, "'{"); int comma = 0; const auto& mapr = nodep->map(); @@ -521,16 +518,16 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { } puts("}"); } - virtual void visit(AstNodeCond* nodep) override { + void visit(AstNodeCond* nodep) override { putbs("("); iterateAndNextConstNull(nodep->condp()); putfs(nodep, " ? "); - iterateAndNextConstNull(nodep->expr1p()); + iterateAndNextConstNull(nodep->thenp()); putbs(" : "); - iterateAndNextConstNull(nodep->expr2p()); + iterateAndNextConstNull(nodep->elsep()); puts(")"); } - virtual void visit(AstRange* nodep) override { + void visit(AstRange* nodep) override { puts("["); if (VN_IS(nodep->leftp(), Const) && VN_IS(nodep->rightp(), Const)) { // Looks nicer if we print [1:0] rather than [32'sh1:32sh0] @@ -545,7 +542,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { puts("]"); } } - virtual void visit(AstSel* nodep) override { + void visit(AstSel* nodep) override { iterateAndNextConstNull(nodep->fromp()); puts("["); if (VN_IS(nodep->lsbp(), Const)) { @@ -569,18 +566,18 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { } puts("]"); } - virtual void visit(AstSliceSel* nodep) override { + void visit(AstSliceSel* nodep) override { iterateAndNextConstNull(nodep->fromp()); puts(cvtToStr(nodep->declRange())); } - virtual void visit(AstTypedef* nodep) override { + void visit(AstTypedef* nodep) override { putfs(nodep, "typedef "); iterateAndNextConstNull(nodep->dtypep()); puts(" "); puts(nodep->prettyName()); puts(";\n"); } - virtual void visit(AstBasicDType* nodep) override { + void visit(AstBasicDType* nodep) override { if (nodep->isSigned()) putfs(nodep, "signed "); putfs(nodep, nodep->prettyName()); if (nodep->rangep()) { @@ -593,15 +590,15 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { puts(":0] "); } } - virtual void visit(AstConstDType* nodep) override { + void visit(AstConstDType* nodep) override { putfs(nodep, "const "); iterate(nodep->subDTypep()); } - virtual void visit(AstNodeArrayDType* nodep) override { + void visit(AstNodeArrayDType* nodep) override { iterate(nodep->subDTypep()); iterateAndNextConstNull(nodep->rangep()); } - virtual void visit(AstNodeUOrStructDType* nodep) override { + void visit(AstNodeUOrStructDType* nodep) override { puts(nodep->verilogKwd() + " "); if (nodep->packed()) puts("packed "); puts("\n"); @@ -609,12 +606,12 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { iterateAndNextConstNull(nodep->membersp()); puts("}"); } - virtual void visit(AstMemberDType* nodep) override { + void visit(AstMemberDType* nodep) override { iterate(nodep->subDTypep()); puts(" "); puts(nodep->name()); } - virtual void visit(AstNodeFTaskRef* nodep) override { + void visit(AstNodeFTaskRef* nodep) override { if (nodep->dotted() != "") { putfs(nodep, nodep->dotted()); puts("."); @@ -626,14 +623,14 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { iterateAndNextConstNull(nodep->pinsp()); puts(")"); } - virtual void visit(AstArg* nodep) override { iterateAndNextConstNull(nodep->exprp()); } - virtual void visit(AstPrintTimeScale* nodep) override { + void visit(AstArg* nodep) override { iterateAndNextConstNull(nodep->exprp()); } + void visit(AstPrintTimeScale* nodep) override { puts(nodep->verilogKwd()); puts(";\n"); } // Terminals - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { if (nodep->varScopep()) { putfs(nodep, nodep->varScopep()->prettyName()); } else { @@ -649,7 +646,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { } } } - virtual void visit(AstVarXRef* nodep) override { + void visit(AstVarXRef* nodep) override { putfs(nodep, nodep->dotted()); puts("."); if (nodep->varp()) { @@ -658,12 +655,12 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { puts(nodep->prettyName()); } } - virtual void visit(AstConst* nodep) override { putfs(nodep, nodep->num().ascii(true, true)); } + void visit(AstConst* nodep) override { putfs(nodep, nodep->num().ascii(true, true)); } // Just iterate - virtual void visit(AstTopScope* nodep) override { iterateChildrenConst(nodep); } - virtual void visit(AstScope* nodep) override { iterateChildrenConst(nodep); } - virtual void visit(AstVar* nodep) override { + void visit(AstTopScope* nodep) override { iterateChildrenConst(nodep); } + void visit(AstScope* nodep) override { iterateChildrenConst(nodep); } + void visit(AstVar* nodep) override { if (nodep->isIO()) { putfs(nodep, nodep->verilogKwd()); puts(" "); @@ -691,21 +688,21 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { } puts(m_suppressVarSemi ? "\n" : ";\n"); } - virtual void visit(AstActive* nodep) override { + void visit(AstActive* nodep) override { m_sensesp = nodep->sensesp(); iterateAndNextConstNull(nodep->stmtsp()); m_sensesp = nullptr; } - virtual void visit(AstParseRef* nodep) override { puts(nodep->prettyName()); } - virtual void visit(AstVarScope*) override {} - virtual void visit(AstNodeText*) override {} - virtual void visit(AstTraceDecl*) override {} - virtual void visit(AstTraceInc*) override {} + void visit(AstParseRef* nodep) override { puts(nodep->prettyName()); } + void visit(AstVarScope*) override {} + void visit(AstNodeText*) override {} + void visit(AstTraceDecl*) override {} + void visit(AstTraceInc*) override {} // NOPs - virtual void visit(AstPragma*) override {} - virtual void visit(AstCell*) override {} // Handled outside the Visit class + void visit(AstPragma*) override {} + void visit(AstCell*) override {} // Handled outside the Visit class // Default - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { puts(std::string{"\n???? // "} + nodep->prettyTypeName() + "\n"); iterateChildrenConst(nodep); // Not v3fatalSrc so we keep processing @@ -720,7 +717,7 @@ public: explicit EmitVBaseVisitor(bool suppressUnknown, AstSenTree* domainp) : m_suppressUnknown{suppressUnknown} , m_sensesp{domainp} {} - virtual ~EmitVBaseVisitor() override = default; + ~EmitVBaseVisitor() override = default; }; //###################################################################### @@ -731,11 +728,11 @@ class EmitVFileVisitor final : public EmitVBaseVisitor { V3OutFile* m_ofp; // METHODS V3OutFile* ofp() const { return m_ofp; } - virtual void puts(const string& str) override { ofp()->puts(str); } - virtual void putbs(const string& str) override { ofp()->putbs(str); } - virtual void putfs(AstNode*, const string& str) override { putbs(str); } - virtual void putqs(AstNode*, const string& str) override { putbs(str); } - virtual void putsNoTracking(const string& str) override { ofp()->putsNoTracking(str); } + void puts(const string& str) override { ofp()->puts(str); } + void putbs(const string& str) override { ofp()->putbs(str); } + void putfs(AstNode*, const string& str) override { putbs(str); } + void putqs(AstNode*, const string& str) override { putbs(str); } + void putsNoTracking(const string& str) override { ofp()->putsNoTracking(str); } public: EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText, bool suppressUnknown) @@ -744,7 +741,7 @@ public: m_trackText = trackText; iterate(nodep); } - virtual ~EmitVFileVisitor() override = default; + ~EmitVFileVisitor() override = default; }; //###################################################################### @@ -754,11 +751,11 @@ class EmitVStreamVisitor final : public EmitVBaseVisitor { // MEMBERS std::ostream& m_os; // METHODS - virtual void putsNoTracking(const string& str) override { m_os << str; } - virtual void puts(const string& str) override { putsNoTracking(str); } - virtual void putbs(const string& str) override { puts(str); } - virtual void putfs(AstNode*, const string& str) override { putbs(str); } - virtual void putqs(AstNode*, const string& str) override { putbs(str); } + void putsNoTracking(const string& str) override { m_os << str; } + void puts(const string& str) override { putsNoTracking(str); } + void putbs(const string& str) override { puts(str); } + void putfs(AstNode*, const string& str) override { putbs(str); } + void putqs(AstNode*, const string& str) override { putbs(str); } public: EmitVStreamVisitor(const AstNode* nodep, std::ostream& os) @@ -766,7 +763,7 @@ public: , m_os(os) { // Need () or GCC 4.8 false warning iterate(const_cast(nodep)); } - virtual ~EmitVStreamVisitor() override = default; + ~EmitVStreamVisitor() override = default; }; //###################################################################### @@ -779,7 +776,7 @@ class EmitVPrefixedFormatter final : public V3OutFormatter { int m_column = 0; // Rough location; need just zero or non-zero FileLine* m_prefixFl; // METHODS - virtual void putcOutput(char chr) override { + void putcOutput(char chr) override { if (chr == '\n') { m_column = 0; m_os << chr; @@ -796,7 +793,7 @@ class EmitVPrefixedFormatter final : public V3OutFormatter { } } - virtual void putsOutput(const char* strg) override { + void putsOutput(const char* strg) override { for (const char* cp = strg; *cp; cp++) putcOutput(*cp); } @@ -812,7 +809,7 @@ public: m_prefixFl = v3Global.rootp()->fileline(); // NETLIST's fileline instead of nullptr to // avoid nullptr checks } - virtual ~EmitVPrefixedFormatter() override { + ~EmitVPrefixedFormatter() override { if (m_column) puts("\n"); } }; @@ -822,13 +819,13 @@ class EmitVPrefixedVisitor final : public EmitVBaseVisitor { EmitVPrefixedFormatter m_formatter; // Special verilog formatter (Way down the // inheritance is another unused V3OutFormatter) // METHODS - virtual void putsNoTracking(const string& str) override { m_formatter.putsNoTracking(str); } - virtual void puts(const string& str) override { m_formatter.puts(str); } + void putsNoTracking(const string& str) override { m_formatter.putsNoTracking(str); } + void puts(const string& str) override { m_formatter.puts(str); } // We don't use m_formatter's putbs because the tokens will change filelines // and insert returns at the proper locations - virtual void putbs(const string& str) override { m_formatter.puts(str); } - virtual void putfs(AstNode* nodep, const string& str) override { putfsqs(nodep, str, false); } - virtual void putqs(AstNode* nodep, const string& str) override { putfsqs(nodep, str, true); } + void putbs(const string& str) override { m_formatter.puts(str); } + void putfs(AstNode* nodep, const string& str) override { putfsqs(nodep, str, false); } + void putqs(AstNode* nodep, const string& str) override { putfsqs(nodep, str, true); } void putfsqs(AstNode* nodep, const string& str, bool quiet) { if (m_formatter.prefixFl() != nodep->fileline()) { m_formatter.prefixFl(nodep->fileline()); @@ -846,7 +843,7 @@ public: if (user3mark) VNUser3InUse::check(); iterate(const_cast(nodep)); } - virtual ~EmitVPrefixedVisitor() override = default; + ~EmitVPrefixedVisitor() override = default; }; //###################################################################### diff --git a/src/V3EmitXml.cpp b/src/V3EmitXml.cpp index 933f27079..89690d6de 100644 --- a/src/V3EmitXml.cpp +++ b/src/V3EmitXml.cpp @@ -26,6 +26,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Emit statements and math operators @@ -39,7 +41,6 @@ class EmitXmlFileVisitor final : public VNVisitor { uint64_t m_id = 0; // METHODS - VL_DEBUG_FUNC; // Declare debug() // Outfile methods V3OutFile* ofp() const { return m_ofp; } @@ -101,11 +102,11 @@ class EmitXmlFileVisitor final : public VNVisitor { } // VISITORS - virtual void visit(AstAssignW* nodep) override { + void visit(AstAssignW* nodep) override { outputTag(nodep, "contassign"); // IEEE: vpiContAssign outputChildrenEnd(nodep, "contassign"); } - virtual void visit(AstCell* nodep) override { + void visit(AstCell* nodep) override { outputTag(nodep, "instance"); // IEEE: vpiInstance puts(" defName="); putsQuoted(nodep->modName()); // IEEE vpiDefName @@ -113,7 +114,7 @@ class EmitXmlFileVisitor final : public VNVisitor { putsQuoted(nodep->origName()); outputChildrenEnd(nodep, "instance"); } - virtual void visit(AstNodeIf* nodep) override { + void visit(AstNodeIf* nodep) override { outputTag(nodep, "if"); puts(">\n"); iterateAndNextNull(nodep->op1p()); @@ -127,7 +128,7 @@ class EmitXmlFileVisitor final : public VNVisitor { } puts("\n"); } - virtual void visit(AstWhile* nodep) override { + void visit(AstWhile* nodep) override { outputTag(nodep, "while"); puts(">\n"); puts("\n"); @@ -150,19 +151,19 @@ class EmitXmlFileVisitor final : public VNVisitor { } puts("\n"); } - virtual void visit(AstNetlist* nodep) override { + void visit(AstNetlist* nodep) override { puts("\n"); iterateChildren(nodep); puts("\n"); } - virtual void visit(AstConstPool* nodep) override { + void visit(AstConstPool* nodep) override { if (!v3Global.opt.xmlOnly()) { puts("\n"); iterateChildren(nodep); puts("\n"); } } - virtual void visit(AstInitArray* nodep) override { + void visit(AstInitArray* nodep) override { puts("\n"); const auto& mapr = nodep->map(); for (const auto& itr : mapr) { @@ -174,7 +175,7 @@ class EmitXmlFileVisitor final : public VNVisitor { } puts("\n"); } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { outputTag(nodep, ""); puts(" origName="); putsQuoted(nodep->origName()); @@ -184,7 +185,7 @@ class EmitXmlFileVisitor final : public VNVisitor { if (nodep->modPublic()) puts(" public=\"true\""); outputChildrenEnd(nodep, ""); } - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { const VVarType typ = nodep->varType(); const string kw = nodep->verilogKwd(); const string vt = nodep->dtypep()->name(); @@ -222,7 +223,7 @@ class EmitXmlFileVisitor final : public VNVisitor { if (nodep->attrSFormat()) puts(" sformat=\"true\""); outputChildrenEnd(nodep, ""); } - virtual void visit(AstPin* nodep) override { + void visit(AstPin* nodep) override { // What we call a pin in verilator is a port in the IEEE spec. outputTag(nodep, "port"); // IEEE: vpiPort if (nodep->modVarp()->isIO()) { @@ -232,12 +233,12 @@ class EmitXmlFileVisitor final : public VNVisitor { // Children includes vpiHighConn and vpiLowConn; we don't support port bits (yet?) outputChildrenEnd(nodep, "port"); } - virtual void visit(AstSenItem* nodep) override { + void visit(AstSenItem* nodep) override { outputTag(nodep, ""); puts(" edgeType=\"" + cvtToStr(nodep->edgeType().ascii()) + "\""); // IEEE vpiTopModule outputChildrenEnd(nodep, ""); } - virtual void visit(AstModportVarRef* nodep) override { + void visit(AstModportVarRef* nodep) override { // Dump direction for Modport references const string kw = nodep->direction().xmlKwd(); outputTag(nodep, ""); @@ -245,13 +246,13 @@ class EmitXmlFileVisitor final : public VNVisitor { putsQuoted(kw); outputChildrenEnd(nodep, ""); } - virtual void visit(AstVarXRef* nodep) override { + void visit(AstVarXRef* nodep) override { outputTag(nodep, ""); puts(" dotted="); putsQuoted(nodep->dotted()); outputChildrenEnd(nodep, ""); } - virtual void visit(AstNodeCCall* nodep) override { + void visit(AstNodeCCall* nodep) override { outputTag(nodep, ""); puts(" func="); putsQuoted(nodep->funcp()->name()); @@ -259,7 +260,7 @@ class EmitXmlFileVisitor final : public VNVisitor { } // Data types - virtual void visit(AstBasicDType* nodep) override { + void visit(AstBasicDType* nodep) override { outputTag(nodep, "basicdtype"); if (nodep->isRanged()) { puts(" left=\"" + cvtToStr(nodep->left()) + "\""); @@ -268,7 +269,7 @@ class EmitXmlFileVisitor final : public VNVisitor { if (nodep->isSigned()) { puts(" signed=\"true\""); } puts("/>\n"); } - virtual void visit(AstIfaceRefDType* nodep) override { + void visit(AstIfaceRefDType* nodep) override { string mpn; outputTag(nodep, ""); if (nodep->isModport()) mpn = nodep->modportName(); @@ -276,19 +277,19 @@ class EmitXmlFileVisitor final : public VNVisitor { putsQuoted(mpn); outputChildrenEnd(nodep, ""); } - virtual void visit(AstDisplay* nodep) override { + void visit(AstDisplay* nodep) override { outputTag(nodep, ""); puts(" displaytype="); putsQuoted(nodep->verilogKwd()); outputChildrenEnd(nodep, ""); } - virtual void visit(AstElabDisplay* nodep) override { + void visit(AstElabDisplay* nodep) override { outputTag(nodep, ""); puts(" displaytype="); putsQuoted(nodep->verilogKwd()); outputChildrenEnd(nodep, ""); } - virtual void visit(AstExtend* nodep) override { + void visit(AstExtend* nodep) override { outputTag(nodep, ""); puts(" width="); putsQuoted(cvtToStr(nodep->width())); @@ -296,7 +297,7 @@ class EmitXmlFileVisitor final : public VNVisitor { putsQuoted(cvtToStr(nodep->lhsp()->widthMinV())); outputChildrenEnd(nodep, ""); } - virtual void visit(AstExtendS* nodep) override { + void visit(AstExtendS* nodep) override { outputTag(nodep, ""); puts(" width="); putsQuoted(cvtToStr(nodep->width())); @@ -306,7 +307,7 @@ class EmitXmlFileVisitor final : public VNVisitor { } // Default - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { outputTag(nodep, ""); outputChildrenEnd(nodep, ""); } @@ -316,7 +317,7 @@ public: : m_ofp{ofp} { iterate(nodep); } - virtual ~EmitXmlFileVisitor() override = default; + ~EmitXmlFileVisitor() override = default; }; //###################################################################### @@ -330,14 +331,13 @@ private: std::deque m_nodeModules; // METHODS - VL_DEBUG_FUNC; // Declare debug() // VISITORS - virtual void visit(AstNetlist* nodep) override { + void visit(AstNetlist* nodep) override { // Children are iterated backwards to ensure correct compilation order iterateChildrenBackwards(nodep); } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { // Only list modules and interfaces // Assumes modules and interfaces list is already sorted level wise if (!nodep->dead() && (VN_IS(nodep, Module) || VN_IS(nodep, Iface)) @@ -346,7 +346,7 @@ private: } } //----- - virtual void visit(AstNode*) override { + void visit(AstNode*) override { // All modules are present at root so no need to iterate on children } @@ -364,7 +364,7 @@ public: } m_os << "\n"; } - virtual ~ModuleFilesXmlVisitor() override = default; + ~ModuleFilesXmlVisitor() override = default; }; //###################################################################### @@ -378,12 +378,11 @@ private: bool m_hasChildren = false; // METHODS - VL_DEBUG_FUNC; // Declare debug() // VISITORS - virtual void visit(AstConstPool*) override {} + void visit(AstConstPool*) override {} - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { if (nodep->level() >= 0 && nodep->level() <= 2) { // ==2 because we don't add wrapper when in XML mode m_os << "\n"; @@ -402,7 +401,7 @@ private: m_os << "\n"; } } - virtual void visit(AstCell* nodep) override { + void visit(AstCell* nodep) override { if (nodep->modp()->dead()) return; if (!m_hasChildren) m_os << ">\n"; m_os << "fileline()->xmlDetailedLocation() << " name=\"" << nodep->name() @@ -422,7 +421,7 @@ private: m_hasChildren = true; } //----- - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -431,7 +430,7 @@ public: // Operate on whole netlist nodep->accept(*this); } - virtual ~HierCellsXmlVisitor() override = default; + ~HierCellsXmlVisitor() override = default; }; //###################################################################### diff --git a/src/V3Error.cpp b/src/V3Error.cpp index be30eae9b..54b61132d 100644 --- a/src/V3Error.cpp +++ b/src/V3Error.cpp @@ -20,6 +20,7 @@ # include "V3Ast.h" # include "V3Global.h" # include "V3Stats.h" +VL_DEFINE_DEBUG_FUNCTIONS; #endif // clang-format on @@ -54,7 +55,7 @@ v3errorIniter v3errorInit; V3ErrorCode::V3ErrorCode(const char* msgp) { // Return error encoding for given string, or ERROR, which is a bad code for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) { - const V3ErrorCode code = V3ErrorCode(codei); + const V3ErrorCode code{codei}; if (0 == VL_STRCASECMP(msgp, code.ascii())) { m_e = code; return; @@ -69,9 +70,9 @@ V3ErrorCode::V3ErrorCode(const char* msgp) { void V3Error::init() { for (int i = 0; i < V3ErrorCode::_ENUM_MAX; i++) { s_describedEachWarn[i] = false; - s_pretendError[i] = V3ErrorCode(i).pretendError(); + s_pretendError[i] = V3ErrorCode{i}.pretendError(); } - if (VL_UNCOVERABLE(string(V3ErrorCode(V3ErrorCode::_ENUM_MAX).ascii()) != " MAX")) { + if (VL_UNCOVERABLE(string(V3ErrorCode{V3ErrorCode::_ENUM_MAX}.ascii()) != " MAX")) { v3fatalSrc("Enum table in V3ErrorCode::EC_ascii() is munged"); } } @@ -275,8 +276,10 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& extra) { s_tellManual = 2; } #ifndef V3ERROR_NO_GLOBAL_ - if (debug()) { + if (dumpTree()) { v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("final.tree", 990)); + } + if (debug()) { if (s_errorExitCb) s_errorExitCb(); V3Stats::statsFinalAll(v3Global.rootp()); V3Stats::statsReport(); diff --git a/src/V3Error.h b/src/V3Error.h index 077260995..4e1de700c 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -142,15 +143,15 @@ public: }; // clang-format on enum en m_e; - inline V3ErrorCode() + V3ErrorCode() : m_e{EC_MIN} {} // cppcheck-suppress noExplicitConstructor - inline V3ErrorCode(en _e) + constexpr V3ErrorCode(en _e) : m_e{_e} {} explicit V3ErrorCode(const char* msgp); // Matching code or ERROR - explicit inline V3ErrorCode(int _e) + explicit V3ErrorCode(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } const char* ascii() const { // clang-format off static const char* const names[] = { @@ -220,16 +221,16 @@ public: || m_e == VARHIDDEN); } }; -inline bool operator==(const V3ErrorCode& lhs, const V3ErrorCode& rhs) { +constexpr bool operator==(const V3ErrorCode& lhs, const V3ErrorCode& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const V3ErrorCode& lhs, V3ErrorCode::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(V3ErrorCode::en lhs, const V3ErrorCode& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const V3ErrorCode& lhs, V3ErrorCode::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(V3ErrorCode::en lhs, const V3ErrorCode& rhs) { return lhs == rhs.m_e; } inline std::ostream& operator<<(std::ostream& os, const V3ErrorCode& rhs) { return os << rhs.ascii(); } -//###################################################################### +// ###################################################################### class V3Error final { // Base class for any object that wants debugging and error reporting @@ -317,7 +318,6 @@ public: }; // Global versions, so that if the class doesn't define a operator, we get the functions anyways. -inline int debug() { return V3Error::debugDefault(); } inline void v3errorEnd(std::ostringstream& sstr) { V3Error::v3errorEnd(sstr); } inline void v3errorEndFatal(std::ostringstream& sstr) { V3Error::v3errorEnd(sstr); @@ -412,19 +412,47 @@ inline void v3errorEndFatal(std::ostringstream& sstr) { V3ERROR_NA; \ return value -/// Declare a convenience debug() routine that may be added to any class in -/// Verilator so that --debugi- will work to control UINFOs in -/// that class: -#define VL_DEBUG_FUNC \ - static int debug() { \ +// Helper macros for VL_DEFINE_DEBUG_FUNCTIONS +#define VL_DEFINE_DEBUG(name) \ + VL_ATTR_UNUSED static int debug##name() { \ static int level = -1; \ if (VL_UNLIKELY(level < 0)) { \ - const int debugSrcLevel = v3Global.opt.debugSrcLevel(__FILE__); \ - if (!v3Global.opt.available()) return debugSrcLevel; \ - level = debugSrcLevel; \ + std::string tag{VL_STRINGIFY(name)}; \ + tag[0] = std::tolower(tag[0]); \ + const unsigned debugTag = v3Global.opt.debugLevel(tag); \ + const unsigned debugSrc = v3Global.opt.debugSrcLevel(__FILE__); \ + const unsigned debugLevel = debugTag >= debugSrc ? debugTag : debugSrc; \ + if (!v3Global.opt.available()) return static_cast(debugLevel); \ + level = static_cast(debugLevel); \ } \ return level; \ - } + } \ + static_assert(true, "") + +#define VL_DEFINE_DUMP(name) \ + VL_ATTR_UNUSED static int dump##name() { \ + static int level = -1; \ + if (VL_UNLIKELY(level < 0)) { \ + std::string tag{VL_STRINGIFY(name)}; \ + tag[0] = std::tolower(tag[0]); \ + const unsigned dumpTag = v3Global.opt.dumpLevel(tag); \ + const unsigned dumpSrc = v3Global.opt.dumpSrcLevel(__FILE__); \ + const unsigned dumpLevel = dumpTag >= dumpSrc ? dumpTag : dumpSrc; \ + if (!v3Global.opt.available()) return static_cast(dumpLevel); \ + level = static_cast(dumpLevel); \ + } \ + return level; \ + } \ + static_assert(true, "") + +// Define debug*() and dump*() routines. This needs to be added to every compilation unit so that +// --debugi- and --dumpi- can be used to control debug prints and dumping +#define VL_DEFINE_DEBUG_FUNCTIONS \ + VL_DEFINE_DEBUG(); /* Define 'int debug()' */ \ + VL_DEFINE_DUMP(); /* Define 'int dump()' */ \ + VL_DEFINE_DUMP(Graph); /* Define 'int dumpGraph()' */ \ + VL_DEFINE_DUMP(Tree); /* Define 'int dumpTree()' */ \ + static_assert(true, "") //---------------------------------------------------------------------- diff --git a/src/V3Expand.cpp b/src/V3Expand.cpp index 6e8e2c1ec..7bba5f825 100644 --- a/src/V3Expand.cpp +++ b/src/V3Expand.cpp @@ -37,6 +37,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Expand state, as a visitor of each AstNode @@ -53,7 +55,6 @@ private: VDouble0 m_statWideLimited; // Statistic tracking // METHODS - VL_DEBUG_FUNC; // Declare debug() bool doExpand(AstNode* nodep) { ++m_statWides; @@ -306,14 +307,14 @@ private: for (int w = 0; w < nodep->widthWords(); ++w) { addWordAssign(nodep, w, new AstCond{fl, rhsp->condp()->cloneTree(true), - newAstWordSelClone(rhsp->expr1p(), w), - newAstWordSelClone(rhsp->expr2p(), w)}); + newAstWordSelClone(rhsp->thenp(), w), + newAstWordSelClone(rhsp->elsep(), w)}); } return true; } // VISITORS - virtual void visit(AstExtend* nodep) override { + void visit(AstExtend* nodep) override { if (nodep->user1SetOnce()) return; // Process once iterateChildren(nodep); if (nodep->isWide()) { @@ -339,7 +340,7 @@ private: } } - virtual void visit(AstSel* nodep) override { + void visit(AstSel* nodep) override { if (nodep->user1SetOnce()) return; // Process once iterateChildren(nodep); // Remember, Sel's may have non-integer rhs, so need to optimize for that! @@ -628,7 +629,7 @@ private: } } - virtual void visit(AstConcat* nodep) override { + void visit(AstConcat* nodep) override { if (nodep->user1SetOnce()) return; // Process once iterateChildren(nodep); if (nodep->isWide()) { @@ -665,7 +666,7 @@ private: return true; } - virtual void visit(AstReplicate* nodep) override { + void visit(AstReplicate* nodep) override { if (nodep->user1SetOnce()) return; // Process once iterateChildren(nodep); if (nodep->isWide()) { @@ -750,10 +751,10 @@ private: VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep); } } - virtual void visit(AstEq* nodep) override { visitEqNeq(nodep); } - virtual void visit(AstNeq* nodep) override { visitEqNeq(nodep); } + void visit(AstEq* nodep) override { visitEqNeq(nodep); } + void visit(AstNeq* nodep) override { visitEqNeq(nodep); } - virtual void visit(AstRedOr* nodep) override { + void visit(AstRedOr* nodep) override { if (nodep->user1SetOnce()) return; // Process once iterateChildren(nodep); FileLine* const fl = nodep->fileline(); @@ -775,7 +776,7 @@ private: VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep); } } - virtual void visit(AstRedAnd* nodep) override { + void visit(AstRedAnd* nodep) override { if (nodep->user1SetOnce()) return; // Process once iterateChildren(nodep); FileLine* const fl = nodep->fileline(); @@ -805,7 +806,7 @@ private: VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep); } } - virtual void visit(AstRedXor* nodep) override { + void visit(AstRedXor* nodep) override { if (nodep->user1SetOnce()) return; // Process once iterateChildren(nodep); if (nodep->lhsp()->isWide()) { @@ -825,7 +826,7 @@ private: // which the inlined function does nicely. } - virtual void visit(AstNodeStmt* nodep) override { + void visit(AstNodeStmt* nodep) override { if (nodep->user1SetOnce()) return; // Process once if (!nodep->isStatement()) { iterateChildren(nodep); @@ -835,7 +836,7 @@ private: iterateChildren(nodep); m_stmtp = nullptr; } - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { if (nodep->user1SetOnce()) return; // Process once m_stmtp = nodep; iterateChildren(nodep); @@ -876,13 +877,13 @@ private: } //-------------------- - virtual void visit(AstVar*) override {} // Don't hit varrefs under vars - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstVar*) override {} // Don't hit varrefs under vars + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit ExpandVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~ExpandVisitor() override { + ~ExpandVisitor() override { V3Stats::addStat("Optimizations, expand wides", m_statWides); V3Stats::addStat("Optimizations, expand wide words", m_statWideWords); V3Stats::addStat("Optimizations, expand limited", m_statWideLimited); @@ -898,5 +899,5 @@ public: void V3Expand::expandAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { ExpandVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("expand", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("expand", 0, dumpTree() >= 3); } diff --git a/src/V3File.cpp b/src/V3File.cpp index 57452b969..a8e23182a 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -56,6 +56,8 @@ #endif // clang-format on +VL_DEFINE_DEBUG_FUNCTIONS; + // If change this code, run a test with the below size set very small // #define INFILTER_IPC_BUFSIZ 16 constexpr int INFILTER_IPC_BUFSIZ = (64 * 1024); // For debug, try this as a small number @@ -94,7 +96,7 @@ class V3FileDependImp final { const string fn = filename(); const int err = stat(fn.c_str(), &m_stat); if (err != 0) { - memset(&m_stat, 0, sizeof(m_stat)); + std::memset(&m_stat, 0, sizeof(m_stat)); m_stat.st_mtime = 1; m_exists = false; // Not an error... This can occur due to `line directives in the .vpp files @@ -146,7 +148,7 @@ V3FileDependImp dependImp; // Depend implementation class //###################################################################### // V3FileDependImp -inline void V3FileDependImp::writeDepend(const string& filename) { +void V3FileDependImp::writeDepend(const string& filename) { const std::unique_ptr ofp{V3File::new_ofstream(filename)}; if (ofp->fail()) v3fatal("Can't write " << filename); @@ -154,7 +156,7 @@ inline void V3FileDependImp::writeDepend(const string& filename) { if (i.target()) *ofp << i.filename() << " "; } *ofp << " : "; - *ofp << v3Global.opt.bin(); + *ofp << v3Global.opt.buildDepBin(); *ofp << " "; for (const DependFile& i : m_filenameList) { @@ -171,7 +173,7 @@ inline void V3FileDependImp::writeDepend(const string& filename) { } } -inline std::vector V3FileDependImp::getAllDeps() const { +std::vector V3FileDependImp::getAllDeps() const { std::vector r; for (const auto& itr : m_filenameList) { if (!itr.target() && itr.exists()) r.push_back(itr.filename()); @@ -179,7 +181,7 @@ inline std::vector V3FileDependImp::getAllDeps() const { return r; } -inline void V3FileDependImp::writeTimes(const string& filename, const string& cmdlineIn) { +void V3FileDependImp::writeTimes(const string& filename, const string& cmdlineIn) { const std::unique_ptr ofp{V3File::new_ofstream(filename)}; if (ofp->fail()) v3fatal("Can't write " << filename); @@ -214,7 +216,7 @@ inline void V3FileDependImp::writeTimes(const string& filename, const string& cm } } -inline bool V3FileDependImp::checkTimes(const string& filename, const string& cmdlineIn) { +bool V3FileDependImp::checkTimes(const string& filename, const string& cmdlineIn) { const std::unique_ptr ifp{V3File::new_ifstream_nodepend(filename)}; if (ifp->fail()) { UINFO(2, " --check-times failed: no input " << filename << endl); @@ -346,7 +348,6 @@ class VInFilterImp final { private: // METHODS - VL_DEBUG_FUNC; // Declare debug() bool readContents(const string& filename, StrList& outl) { if (m_pid) { @@ -389,7 +390,7 @@ private: if (!m_pidExited && waitpid(m_pid, &m_pidStatus, hang ? 0 : WNOHANG)) { UINFO(1, "--pipe-filter: Exited, status " << m_pidStatus << " exit=" << WEXITSTATUS(m_pidStatus) << " err" - << strerror(errno) << endl); + << std::strerror(errno) << endl); m_readEof = true; m_pidExited = true; } @@ -495,7 +496,7 @@ private: constexpr int P_WR = 1; if (pipe(fd_stdin) != 0 || pipe(fd_stdout) != 0) { - v3fatal("--pipe-filter: Can't pipe: " << strerror(errno)); + v3fatal("--pipe-filter: Can't pipe: " << std::strerror(errno)); } if (fd_stdin[P_RD] <= 2 || fd_stdin[P_WR] <= 2 || fd_stdout[P_RD] <= 2 || fd_stdout[P_WR] <= 2) { @@ -507,7 +508,7 @@ private: UINFO(1, "--pipe-filter: /bin/sh -c " << command << endl); const pid_t pid = fork(); - if (pid < 0) v3fatal("--pipe-filter: fork failed: " << strerror(errno)); + if (pid < 0) v3fatal("--pipe-filter: fork failed: " << std::strerror(errno)); if (pid == 0) { // Child UINFO(6, "In child\n"); close(fd_stdin[P_WR]); @@ -518,7 +519,7 @@ private: execl("/bin/sh", "sh", "-c", command.c_str(), static_cast(nullptr)); // Don't use v3fatal, we don't share the common structures any more - fprintf(stderr, "--pipe-filter: exec failed: %s\n", strerror(errno)); + fprintf(stderr, "--pipe-filter: exec failed: %s\n", std::strerror(errno)); _exit(1); } else { // Parent UINFO(6, "In parent, child pid " << pid << " stdin " << fd_stdin[P_WR] << "->" diff --git a/src/V3File.h b/src/V3File.h index 309f136c9..38f4dc6ff 100644 --- a/src/V3File.h +++ b/src/V3File.h @@ -206,7 +206,7 @@ public: V3OutFile(V3OutFile&&) = delete; V3OutFile& operator=(V3OutFile&&) = delete; - virtual ~V3OutFile() override; + ~V3OutFile() override; void putsForceIncs(); private: @@ -216,15 +216,15 @@ private: } // CALLBACKS - virtual void putcOutput(char chr) override { + void putcOutput(char chr) override { m_bufferp->at(m_usedBytes++) = chr; if (VL_UNLIKELY(m_usedBytes >= WRITE_BUFFER_SIZE_BYTES)) writeBlock(); } - virtual void putsOutput(const char* str) override { + void putsOutput(const char* str) override { std::size_t len = strlen(str); std::size_t availableBytes = WRITE_BUFFER_SIZE_BYTES - m_usedBytes; while (VL_UNLIKELY(len >= availableBytes)) { - memcpy(m_bufferp->data() + m_usedBytes, str, availableBytes); + std::memcpy(m_bufferp->data() + m_usedBytes, str, availableBytes); m_usedBytes = WRITE_BUFFER_SIZE_BYTES; writeBlock(); str += availableBytes; @@ -232,7 +232,7 @@ private: availableBytes = WRITE_BUFFER_SIZE_BYTES; } if (len > 0) { - memcpy(m_bufferp->data() + m_usedBytes, str, len); + std::memcpy(m_bufferp->data() + m_usedBytes, str, len); m_usedBytes += len; } } @@ -246,7 +246,7 @@ public: : V3OutFile{filename, V3OutFormatter::LA_C} { resetPrivate(); } - virtual ~V3OutCFile() override = default; + ~V3OutCFile() override = default; virtual void putsHeader() { puts("// Verilated -*- C++ -*-\n"); } virtual void putsIntTopInclude() { putsForceIncs(); } virtual void putsGuard(); @@ -270,9 +270,9 @@ class V3OutScFile final : public V3OutCFile { public: explicit V3OutScFile(const string& filename) : V3OutCFile{filename} {} - virtual ~V3OutScFile() override = default; - virtual void putsHeader() override { puts("// Verilated -*- SystemC -*-\n"); } - virtual void putsIntTopInclude() override { + ~V3OutScFile() override = default; + void putsHeader() override { puts("// Verilated -*- SystemC -*-\n"); } + void putsIntTopInclude() override { putsForceIncs(); puts("#include \"systemc.h\"\n"); puts("#include \"verilated_sc.h\"\n"); @@ -283,7 +283,7 @@ class V3OutVFile final : public V3OutFile { public: explicit V3OutVFile(const string& filename) : V3OutFile{filename, V3OutFormatter::LA_VERILOG} {} - virtual ~V3OutVFile() override = default; + ~V3OutVFile() override = default; virtual void putsHeader() { puts("// Verilated -*- Verilog -*-\n"); } }; @@ -293,7 +293,7 @@ public: : V3OutFile{filename, V3OutFormatter::LA_XML} { blockIndent(2); } - virtual ~V3OutXmlFile() override = default; + ~V3OutXmlFile() override = default; virtual void putsHeader() { puts("\n"); } }; @@ -301,7 +301,7 @@ class V3OutMkFile final : public V3OutFile { public: explicit V3OutMkFile(const string& filename) : V3OutFile{filename, V3OutFormatter::LA_MK} {} - virtual ~V3OutMkFile() override = default; + ~V3OutMkFile() override = default; virtual void putsHeader() { puts("# Verilated -*- Makefile -*-\n"); } // No automatic indentation yet. void puts(const char* strg) { putsNoTracking(strg); } diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index 6b7b2e58b..2e1c76afe 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -31,12 +31,15 @@ #include #include +#include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // FileLineSingleton class functions -string FileLineSingleton::filenameLetters(int fileno) { +string FileLineSingleton::filenameLetters(fileNameIdx_t fileno) { constexpr int size = 1 + (64 / 4); // Each letter retires more than 4 bits of a > 64 bit number char out[size]; @@ -58,14 +61,18 @@ string FileLineSingleton::filenameLetters(int fileno) { //! We associate a language with each source file, so we also set the default //! for this. -int FileLineSingleton::nameToNumber(const string& filename) { - const auto it = vlstd::as_const(m_namemap).find(filename); - if (VL_LIKELY(it != m_namemap.end())) return it->second; - const int num = m_names.size(); - m_names.push_back(filename); - m_languages.push_back(V3LangCode::mostRecent()); - m_namemap.emplace(filename, num); - return num; +FileLineSingleton::fileNameIdx_t FileLineSingleton::nameToNumber(const string& filename) { + const auto pair = m_namemap.emplace(filename, 0); + fileNameIdx_t& idx = pair.first->second; + if (pair.second) { + const size_t nextIdx = m_names.size(); + UASSERT(nextIdx <= std::numeric_limits::max(), + "Too many input files (" + cvtToStr(nextIdx) + "+)."); + idx = static_cast(nextIdx); + m_names.push_back(filename); + m_languages.push_back(V3LangCode::mostRecent()); + } + return idx; } //! Support XML output @@ -80,15 +87,47 @@ void FileLineSingleton::fileNameNumMapDumpXml(std::ostream& os) { os << "\n"; } -//###################################################################### -// VFileContents class functions - -int VFileContent::debug() { - static int level = -1; - if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__); - return level; +FileLineSingleton::msgEnSetIdx_t FileLineSingleton::addMsgEnBitSet(const MsgEnBitSet& bitSet) { + const auto pair = m_internedMsgEnIdxs.emplace(bitSet, 0); + msgEnSetIdx_t& idx = pair.first->second; + if (pair.second) { + const size_t nextIdx = m_internedMsgEns.size(); + UASSERT(nextIdx <= std::numeric_limits::max(), + "Too many unique message enable sets (" + cvtToStr(nextIdx) + "+)."); + idx = static_cast(nextIdx); + m_internedMsgEns.push_back(bitSet); + } + return idx; } +FileLineSingleton::msgEnSetIdx_t FileLineSingleton::defaultMsgEnIndex() { + MsgEnBitSet msgEnBitSet; + for (int i = V3ErrorCode::EC_MIN; i < V3ErrorCode::_ENUM_MAX; ++i) { + msgEnBitSet.set(i, !V3ErrorCode{i}.defaultsOff()); + } + return addMsgEnBitSet(msgEnBitSet); +} + +FileLineSingleton::msgEnSetIdx_t FileLineSingleton::msgEnSetBit(msgEnSetIdx_t setIdx, + size_t bitIdx, bool value) { + if (msgEn(setIdx).test(bitIdx) == value) return setIdx; + MsgEnBitSet msgEnBitSet{msgEn(setIdx)}; + msgEnBitSet.set(bitIdx, value); + return addMsgEnBitSet(msgEnBitSet); +} + +FileLineSingleton::msgEnSetIdx_t FileLineSingleton::msgEnAnd(msgEnSetIdx_t lhsIdx, + msgEnSetIdx_t rhsIdx) { + MsgEnBitSet msgEnBitSet{msgEn(lhsIdx)}; + msgEnBitSet &= msgEn(rhsIdx); + if (msgEnBitSet == msgEn(lhsIdx)) return lhsIdx; + if (msgEnBitSet == msgEn(rhsIdx)) return rhsIdx; + return addMsgEnBitSet(msgEnBitSet); +} + +// ###################################################################### +// VFileContents class functions + void VFileContent::pushText(const string& text) { if (m_lines.size() == 0) { m_lines.emplace_back(""); // no such thing as line [0] @@ -140,22 +179,17 @@ std::ostream& operator<<(std::ostream& os, VFileContent* contentp) { return os; } -//###################################################################### -// FileLine class functions +// ###################################################################### +// FileLine class functions -// Sort of a singleton -FileLine::FileLine(FileLine::EmptySecret) { - m_filenameno = singleton().nameToNumber(FileLine::builtInFilename()); - - m_warnOn = 0; - for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) { - const V3ErrorCode code = V3ErrorCode(codei); - warnOff(code, code.defaultsOff()); - } +FileLine::~FileLine() { + if (m_contentp) VL_DO_DANGLING(m_contentp->refDec(), m_contentp); } void FileLine::newContent() { - m_contentp = std::make_shared(); + if (m_contentp) VL_DO_DANGLING(m_contentp->refDec(), m_contentp); + m_contentp = new VFileContent; + m_contentp->refInc(); m_contentLineno = 1; } @@ -185,7 +219,7 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) { const char* const ln = textp; while (*textp && !isspace(*textp)) textp++; if (isdigit(*ln)) { - lineno(atoi(ln)); + lineno(std::atoi(ln)); } else { fail = true; } @@ -207,7 +241,7 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) { // Grab level while (*textp && (isspace(*textp) || *textp == '"')) textp++; if (isdigit(*textp)) { - enterExitRef = atoi(textp); + enterExitRef = std::atoi(textp); if (enterExitRef >= 3) fail = true; } else { enterExitRef = 0; @@ -309,37 +343,29 @@ bool FileLine::warnOff(const string& msg, bool flag) { void FileLine::warnLintOff(bool flag) { for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) { - const V3ErrorCode code = V3ErrorCode(codei); + const V3ErrorCode code{codei}; if (code.lintError()) warnOff(code, flag); } } void FileLine::warnStyleOff(bool flag) { for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) { - const V3ErrorCode code = V3ErrorCode(codei); + const V3ErrorCode code{codei}; if (code.styleError()) warnOff(code, flag); } } bool FileLine::warnIsOff(V3ErrorCode code) const { - if (!m_warnOn.test(code)) return true; - if (!defaultFileLine().m_warnOn.test(code)) return true; // Global overrides local + if (!msgEn().test(code)) return true; + if (!defaultFileLine().msgEn().test(code)) return true; // Global overrides local // UNOPTFLAT implies UNOPT - if (code == V3ErrorCode::UNOPT && !m_warnOn.test(V3ErrorCode::UNOPTFLAT)) return true; - if ((code.lintError() || code.styleError()) && !m_warnOn.test(V3ErrorCode::I_LINT)) { + if (code == V3ErrorCode::UNOPT && !msgEn().test(V3ErrorCode::UNOPTFLAT)) return true; + if ((code.lintError() || code.styleError()) && !msgEn().test(V3ErrorCode::I_LINT)) { return true; } return false; } -void FileLine::modifyStateInherit(const FileLine* fromp) { - // Any warnings that are off in "from", become off in "this". - for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) { - const V3ErrorCode code = V3ErrorCode(codei); - if (fromp->warnIsOff(code)) warnOff(code, true); - } -} - void FileLine::v3errorEnd(std::ostringstream& sstr, const string& extra) { std::ostringstream nsstr; if (lastLineno()) nsstr << this; diff --git a/src/V3FileLine.h b/src/V3FileLine.h index f16bc5bca..c8a44a0bf 100644 --- a/src/V3FileLine.h +++ b/src/V3FileLine.h @@ -23,14 +23,17 @@ #include "V3Error.h" #include "V3LangCode.h" +#include #include #include #include #include #include #include +#include +#include -//###################################################################### +// ###################################################################### class FileLine; @@ -39,69 +42,109 @@ class FileLine; //! This singleton class contains tables of data that are unchanging in each //! source file (each with its own unique filename number). class FileLineSingleton final { + friend class FileLine; + + // TYPES + using fileNameIdx_t = uint16_t; // Increase width if 64K input files are not enough + using msgEnSetIdx_t = uint16_t; // Increase width if 64K unique message sets are not enough + using MsgEnBitSet = std::bitset; + // MEMBERS - std::map m_namemap; // filenameno for each filename + std::map m_namemap; // filenameno for each filename std::deque m_names; // filename text for each filenameno std::deque m_languages; // language for each filenameno + + // Map from flag set to the index in m_internedMsgEns for interning + std::unordered_map m_internedMsgEnIdxs; + // Interned message enablement flag sets + std::vector m_internedMsgEns; + // CONSTRUCTORS FileLineSingleton() = default; ~FileLineSingleton() = default; -protected: - friend class FileLine; - int nameToNumber(const string& filename); - string numberToName(int filenameno) const { return m_names[filenameno]; } - V3LangCode numberToLang(int filenameno) const { return m_languages[filenameno]; } - void numberToLang(int filenameno, const V3LangCode& l) { m_languages[filenameno] = l; } + fileNameIdx_t nameToNumber(const string& filename); + string numberToName(fileNameIdx_t filenameno) const { return m_names[filenameno]; } + V3LangCode numberToLang(fileNameIdx_t filenameno) const { return m_languages[filenameno]; } + void numberToLang(fileNameIdx_t filenameno, const V3LangCode& l) { + m_languages[filenameno] = l; + } void clear() { m_namemap.clear(); m_names.clear(); m_languages.clear(); } void fileNameNumMapDumpXml(std::ostream& os); - static string filenameLetters(int fileno); + static string filenameLetters(fileNameIdx_t fileno); + + // Add given bitset to the interned bitsets, return interned index + msgEnSetIdx_t addMsgEnBitSet(const MsgEnBitSet& bitSet); + // Add index of default bitset + msgEnSetIdx_t defaultMsgEnIndex(); + // Set bitIdx to value in bitset at interned idnex setIdx, return interned index of result + msgEnSetIdx_t msgEnSetBit(msgEnSetIdx_t setIdx, size_t bitIdx, bool value); + // Return index to intersection set + msgEnSetIdx_t msgEnAnd(msgEnSetIdx_t lhsIdx, msgEnSetIdx_t rhsIdx); + // Retrieve interned bitset at given interned index. The returned reference is not persistent. + const MsgEnBitSet& msgEn(msgEnSetIdx_t idx) const { return m_internedMsgEns.at(idx); } }; -//! All source lines from a file/stream, to enable errors to show sources +// All source lines from a file/stream, to enable errors to show sources class VFileContent final { + friend class FileLine; // MEMBERS int m_id; // Content ID number + // Reference count for sharing (shared_ptr has size overhead that we don't want) + std::atomic m_refCount{0}; std::deque m_lines; // Source text lines -public: VFileContent() { static int s_id = 0; m_id = ++s_id; } ~VFileContent() = default; // METHODS + void refInc() { ++m_refCount; } + void refDec() { + if (!--m_refCount) delete this; + } + +public: void pushText(const string& text); // Add arbitrary text (need not be line-by-line) string getLine(int lineno) const; string ascii() const { return "ct" + cvtToStr(m_id); } - static int debug(); }; std::ostream& operator<<(std::ostream& os, VFileContent* contentp); -//! File and line number of an object, mostly for error reporting +// File and line number of an object, mostly for error reporting -//! This class is instantiated for every source code line (potentially -//! millions). To save space, per-file information (e.g. filename, source -//! language is held in tables in the FileLineSingleton class. +// This class is instantiated for every source code line (potentially millions), and instances +// created at any point usually persist until the end of the program. To save space, per-file +// information (e.g. filename, source language) is held in tables in the FileLineSingleton class. +// Similarly, message enablement flags are interned in FileLineSingleton. + +// WARNING: Avoid increasing the size of this class as much as possible. class FileLine final { + // CONSTANTS static constexpr unsigned SHOW_SOURCE_MAX_LENGTH = 400; // Don't show source lines > this long + // TYPES + using fileNameIdx_t = FileLineSingleton::fileNameIdx_t; + using msgEnSetIdx_t = FileLineSingleton::msgEnSetIdx_t; + using MsgEnBitSet = FileLineSingleton::MsgEnBitSet; + // MEMBERS // Columns here means number of chars from beginning (i.e. tabs count as one) + msgEnSetIdx_t m_msgEnIdx = 0; // Message enable bit set (index into interned array) + fileNameIdx_t m_filenameno = 0; // `line corrected filename number + bool m_waive : 1; // Waive warning - pack next to the line number to save 8 bytes of storage + unsigned m_contentLineno : 31; // Line number within source stream int m_firstLineno = 0; // `line corrected token's first line number int m_firstColumn = 0; // `line corrected token's first column number int m_lastLineno = 0; // `line corrected token's last line number int m_lastColumn = 0; // `line corrected token's last column number - int m_filenameno; // `line corrected filename number - int m_contentLineno = 0; // Line number within source stream - std::shared_ptr m_contentp = nullptr; // Source text contents line is within + VFileContent* m_contentp = nullptr; // Source text contents line is within FileLine* m_parent = nullptr; // Parent line that included this line - std::bitset m_warnOn; - bool m_waive = false; // Waive warning protected: // User routines should never need to change line numbers @@ -119,30 +162,38 @@ private: return s; } static FileLine& defaultFileLine() { - static FileLine* defFilelinep = new FileLine(FileLine::EmptySecret()); - return *defFilelinep; + static FileLine s; + return s; } + FileLine() // Only used for defaultFileLine above + : m_msgEnIdx{singleton().defaultMsgEnIndex()} + , m_filenameno{singleton().nameToNumber(FileLine::builtInFilename())} + , m_waive{false} + , m_contentLineno{0} {} + public: explicit FileLine(const string& filename) - : m_filenameno{singleton().nameToNumber(filename)} - , m_warnOn{defaultFileLine().m_warnOn} {} + : m_msgEnIdx{defaultFileLine().m_msgEnIdx} + , m_filenameno{singleton().nameToNumber(filename)} + , m_waive{false} + , m_contentLineno{0} {} explicit FileLine(FileLine* fromp) - : m_firstLineno{fromp->m_firstLineno} + : m_msgEnIdx{fromp->m_msgEnIdx} + , m_filenameno{fromp->m_filenameno} + , m_waive{fromp->m_waive} + , m_contentLineno{fromp->m_contentLineno} + , m_firstLineno{fromp->m_firstLineno} , m_firstColumn{fromp->m_firstColumn} , m_lastLineno{fromp->m_lastLineno} , m_lastColumn{fromp->m_lastColumn} - , m_filenameno{fromp->m_filenameno} - , m_contentLineno{fromp->m_contentLineno} , m_contentp{fromp->m_contentp} - , m_parent{fromp->m_parent} - , m_warnOn{fromp->m_warnOn} - , m_waive{fromp->m_waive} {} - struct EmptySecret {}; // Constructor selection - explicit FileLine(EmptySecret); + , m_parent{fromp->m_parent} { + if (m_contentp) m_contentp->refInc(); + } FileLine* copyOrSameFileLine(); static void deleteAllRemaining(); - ~FileLine() = default; + ~FileLine(); #ifdef VL_LEAK_CHECKS static void* operator new(size_t size); static void operator delete(void* obj, size_t size); @@ -151,7 +202,7 @@ public: void newContent(); void contentLineno(int num) { lineno(num); - m_contentLineno = num; + m_contentLineno = static_cast(num); } void lineno(int num) { m_firstLineno = num; @@ -181,7 +232,7 @@ public: int firstColumn() const { return m_firstColumn; } int lastLineno() const { return m_lastLineno; } int lastColumn() const { return m_lastColumn; } - std::shared_ptr contentp() const { return m_contentp; } + VFileContent* contentp() const { return m_contentp; } // If not otherwise more specific, use last lineno for errors etc, // as the parser errors etc generally make more sense pointing at the last parse point int lineno() const { return m_lastLineno; } @@ -205,22 +256,24 @@ public: string lineDirectiveStrg(int enterExit) const; // Turn on/off warning messages on this line. - void warnOn(V3ErrorCode code, bool flag) { m_warnOn.set(code, flag); } + void warnOn(V3ErrorCode code, bool flag) { + m_msgEnIdx = singleton().msgEnSetBit(m_msgEnIdx, code, flag); + } void warnOff(V3ErrorCode code, bool flag) { warnOn(code, !flag); } bool warnOff(const string& msg, bool flag); // Returns 1 if ok bool warnIsOff(V3ErrorCode code) const; void warnLintOff(bool flag); void warnStyleOff(bool flag); - void warnStateFrom(const FileLine& from) { m_warnOn = from.m_warnOn; } + void warnStateFrom(const FileLine& from) { m_msgEnIdx = from.m_msgEnIdx; } void warnResetDefault() { warnStateFrom(defaultFileLine()); } bool lastWarnWaived() const { return m_waive; } // Specific flag ACCESSORS/METHODS - bool celldefineOn() const { return m_warnOn.test(V3ErrorCode::I_CELLDEFINE); } + bool celldefineOn() const { return msgEn().test(V3ErrorCode::I_CELLDEFINE); } void celldefineOn(bool flag) { warnOn(V3ErrorCode::I_CELLDEFINE, flag); } - bool coverageOn() const { return m_warnOn.test(V3ErrorCode::I_COVERAGE); } + bool coverageOn() const { return msgEn().test(V3ErrorCode::I_COVERAGE); } void coverageOn(bool flag) { warnOn(V3ErrorCode::I_COVERAGE, flag); } - bool tracingOn() const { return m_warnOn.test(V3ErrorCode::I_TRACING); } + bool tracingOn() const { return msgEn().test(V3ErrorCode::I_TRACING); } void tracingOn(bool flag) { warnOn(V3ErrorCode::I_TRACING, flag); } // METHODS - Global @@ -239,7 +292,9 @@ public: // METHODS - Called from netlist // Merge warning disables from another fileline - void modifyStateInherit(const FileLine* fromp); + void modifyStateInherit(const FileLine* fromp) { + m_msgEnIdx = singleton().msgEnAnd(m_msgEnIdx, fromp->m_msgEnIdx); + } // Change the current fileline due to actions discovered after parsing // and may have side effects on other nodes sharing this FileLine. // Use only when this is intended @@ -247,7 +302,11 @@ public: // OPERATORS void v3errorEnd(std::ostringstream& str, const string& extra = ""); - void v3errorEndFatal(std::ostringstream& str) VL_ATTR_NORETURN; + void v3errorEndFatal(std::ostringstream& str) VL_ATTR_NORETURN { + v3errorEnd(str); + assert(0); // LCOV_EXCL_LINE + VL_UNREACHABLE + } /// When building an error, prefix for printing continuation lines /// e.g. information referring to the same FileLine as before string warnMore() const; @@ -263,7 +322,7 @@ public: bool operator==(const FileLine& rhs) const { return (m_firstLineno == rhs.m_firstLineno && m_firstColumn == rhs.m_firstColumn && m_lastLineno == rhs.m_lastLineno && m_lastColumn == rhs.m_lastColumn - && m_filenameno == rhs.m_filenameno && m_warnOn == rhs.m_warnOn); + && m_filenameno == rhs.m_filenameno && m_msgEnIdx == rhs.m_msgEnIdx); } // Returns -1 if (*this) should come before rhs after sorted. 1 for the opposite case. 0 for // equivalent. @@ -275,21 +334,16 @@ public: return (m_firstColumn < rhs.m_firstColumn) ? -1 : 1; if (m_lastLineno != rhs.m_lastLineno) return (m_lastLineno < rhs.m_lastLineno) ? -1 : 1; if (m_lastColumn != rhs.m_lastColumn) return (m_lastColumn < rhs.m_lastColumn) ? -1 : 1; - for (size_t i = 0; i < m_warnOn.size(); ++i) { - if (m_warnOn[i] != rhs.m_warnOn[i]) return (m_warnOn[i] < rhs.m_warnOn[i]) ? -1 : 1; + for (size_t i = 0; i < msgEn().size(); ++i) { + if (msgEn().test(i) != rhs.msgEn().test(i)) return rhs.msgEn().test(i) ? -1 : 1; } return 0; // (*this) and rhs are equivalent } private: string warnContext(bool secondary) const; + const MsgEnBitSet& msgEn() const { return singleton().msgEn(m_msgEnIdx); } }; std::ostream& operator<<(std::ostream& os, FileLine* fileline); -inline void FileLine::v3errorEndFatal(std::ostringstream& str) { - v3errorEnd(str); - assert(0); // LCOV_EXCL_LINE - VL_UNREACHABLE -} - #endif // Guard diff --git a/src/V3Force.cpp b/src/V3Force.cpp index ea4c61a02..bebf210ac 100644 --- a/src/V3Force.cpp +++ b/src/V3Force.cpp @@ -46,6 +46,8 @@ #include "V3Error.h" #include "V3Global.h" +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Convert force/release statements and signals marked 'forceable' @@ -109,7 +111,7 @@ class ForceConvertVisitor final : public VNVisitor { new AstSenTree{flp, new AstSenItem{flp, AstSenItem::Initial{}}}}; activep->sensesStorep(activep->sensesp()); activep->addStmtsp(new AstInitial{flp, assignp}); - vscp->scopep()->addActivep(activep); + vscp->scopep()->addBlocksp(activep); } { // Add the combinational override @@ -127,7 +129,7 @@ class ForceConvertVisitor final : public VNVisitor { new AstSenTree{flp, new AstSenItem{flp, AstSenItem::Combo{}}}}; activep->sensesStorep(activep->sensesp()); activep->addStmtsp(new AstAssignW{flp, lhsp, rhsp}); - vscp->scopep()->addActivep(activep); + vscp->scopep()->addBlocksp(activep); } } }; @@ -305,5 +307,5 @@ void V3Force::forceAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); if (!v3Global.hasForceableSignals()) return; ForceConvertVisitor::apply(nodep); - V3Global::dumpCheckGlobalTree("force", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("force", 0, dumpTree() >= 3); } diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 88a9332d4..6829d55ee 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -39,6 +39,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + class GateDedupeVarVisitor; using GateVarRefList = std::list; @@ -47,13 +49,6 @@ constexpr int GATE_DEDUP_MAX_DEPTH = 20; //###################################################################### -class GateBaseVisitor VL_NOT_FINAL : public VNVisitor { -public: - VL_DEBUG_FUNC; // Declare debug() -}; - -//###################################################################### - class GateLogicVertex; class GateVarVertex; class GateGraphBaseVisitor VL_NOT_FINAL { @@ -62,9 +57,8 @@ public: explicit GateGraphBaseVisitor(V3Graph* graphp) : m_graphp{graphp} {} virtual ~GateGraphBaseVisitor() = default; - virtual VNUser visit(GateLogicVertex* vertexp, VNUser vu = VNUser(0)) = 0; - virtual VNUser visit(GateVarVertex* vertexp, VNUser vu = VNUser(0)) = 0; - VL_DEBUG_FUNC; // Declare debug() + virtual VNUser visit(GateLogicVertex* vertexp, VNUser vu = VNUser{0}) = 0; + virtual VNUser visit(GateVarVertex* vertexp, VNUser vu = VNUser{0}) = 0; }; //###################################################################### @@ -79,9 +73,9 @@ public: GateEitherVertex(V3Graph* graphp, AstScope* scopep) : V3GraphVertex{graphp} , m_scopep{scopep} {} - virtual ~GateEitherVertex() override = default; + ~GateEitherVertex() override = default; // ACCESSORS - virtual string dotStyle() const override { return m_consumed ? "" : "dotted"; } + string dotStyle() const override { return m_consumed ? "" : "dotted"; } AstScope* scopep() const { return m_scopep; } bool reducible() const { return m_reducible; } bool dedupable() const { return m_dedupable; } @@ -102,12 +96,12 @@ public: clearReducible(nonReducibleReason); clearDedupable(nonReducibleReason); } - virtual VNUser accept(GateGraphBaseVisitor& v, VNUser vu = VNUser(0)) = 0; + virtual VNUser accept(GateGraphBaseVisitor& v, VNUser vu = VNUser{0}) = 0; // Returns only the result from the LAST vertex iterated over - VNUser iterateInEdges(GateGraphBaseVisitor& v, VNUser vu = VNUser(0)) { - VNUser ret = VNUser(0); + VNUser iterateInEdges(GateGraphBaseVisitor& v, VNUser vu = VNUser{0}) { + VNUser ret{0}; for (V3GraphEdge* edgep = inBeginp(); edgep; edgep = edgep->inNextp()) { - ret = dynamic_cast(edgep->fromp())->accept(v, vu); + ret = static_cast(edgep->fromp())->accept(v, vu); } return ret; } @@ -115,13 +109,13 @@ public: // Note: This behaves differently than iterateInEdges() in that it will traverse // all edges that exist when it is initially called, whereas // iterateInEdges() will stop traversing edges if one is deleted - VNUser iterateCurrentOutEdges(GateGraphBaseVisitor& v, VNUser vu = VNUser(0)) { - VNUser ret = VNUser(0); + VNUser iterateCurrentOutEdges(GateGraphBaseVisitor& v, VNUser vu = VNUser{0}) { + VNUser ret{0}; V3GraphEdge* next_edgep = nullptr; for (V3GraphEdge* edgep = outBeginp(); edgep; edgep = next_edgep) { // Need to find the next edge before visiting in case the edge is deleted next_edgep = edgep->outNextp(); - ret = dynamic_cast(edgep->top())->accept(v, vu); + ret = static_cast(edgep->top())->accept(v, vu); } return ret; } @@ -137,11 +131,11 @@ public: GateVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) : GateEitherVertex{graphp, scopep} , m_varScp{varScp} {} - virtual ~GateVarVertex() override = default; + ~GateVarVertex() override = default; // ACCESSORS AstVarScope* varScp() const { return m_varScp; } - virtual string name() const override { return (cvtToHex(m_varScp) + " " + varScp()->name()); } - virtual string dotColor() const override { return "blue"; } + string name() const override { return (cvtToHex(m_varScp) + " " + varScp()->name()); } + string dotColor() const override { return "blue"; } bool isTop() const { return m_isTop; } void setIsTop() { m_isTop = true; } bool isClock() const { return m_isClock; } @@ -162,7 +156,7 @@ public: setIsClock(); } } - virtual VNUser accept(GateGraphBaseVisitor& v, VNUser vu = VNUser(0)) override { + VNUser accept(GateGraphBaseVisitor& v, VNUser vu = VNUser{0}) override { return v.visit(this, vu); } }; @@ -178,17 +172,15 @@ public: , m_nodep{nodep} , m_activep{activep} , m_slow{slow} {} - virtual ~GateLogicVertex() override = default; + ~GateLogicVertex() override = default; // ACCESSORS - virtual string name() const override { - return (cvtToHex(m_nodep) + "@" + scopep()->prettyName()); - } - virtual string dotColor() const override { return "purple"; } - virtual FileLine* fileline() const override { return nodep()->fileline(); } + string name() const override { return (cvtToHex(m_nodep) + "@" + scopep()->prettyName()); } + string dotColor() const override { return "purple"; } + FileLine* fileline() const override { return nodep()->fileline(); } AstNode* nodep() const { return m_nodep; } AstActive* activep() const { return m_activep; } bool slow() const { return m_slow; } - virtual VNUser accept(GateGraphBaseVisitor& v, VNUser vu = VNUser(0)) override { + VNUser accept(GateGraphBaseVisitor& v, VNUser vu = VNUser{0}) override { return v.visit(this, vu); } }; @@ -196,7 +188,7 @@ public: //###################################################################### // Is this a simple math expression with a single input and single output? -class GateOkVisitor final : public GateBaseVisitor { +class GateOkVisitor final : public VNVisitor { private: // RETURN STATE bool m_isSimple = true; // Set false when we know it isn't simple @@ -217,7 +209,7 @@ private: } } // VISITORS - virtual void visit(AstNodeVarRef* nodep) override { + void visit(AstNodeVarRef* nodep) override { ++m_ops; iterateChildren(nodep); // We only allow a LHS ref for the var being set, and a RHS ref for @@ -243,7 +235,7 @@ private: m_rhsVarRefs.push_back(nodep); } } - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { m_substTreep = nodep->rhsp(); if (!VN_IS(nodep->lhsp(), NodeVarRef)) { clearSimple("ASSIGN(non-VARREF)"); @@ -264,7 +256,7 @@ private: } } //-------------------- - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { // *** Special iterator if (!m_isSimple) return; // Fastpath if (++m_ops > v3Global.opt.gateStmts()) clearSimple("--gate-stmts exceeded"); @@ -294,7 +286,7 @@ public: } if (debug() >= 9 && !m_isSimple) nodep->dumpTree(cout, " gate!Ok: "); } - virtual ~GateOkVisitor() override = default; + ~GateOkVisitor() override = default; // PUBLIC METHODS bool isSimple() const { return m_isSimple; } AstNode* substTree() const { return m_substTreep; } @@ -311,7 +303,7 @@ static void eliminate(AstNode* logicp, // ###################################################################### // Gate class functions -class GateVisitor final : public GateBaseVisitor { +class GateVisitor final : public VNVisitor { private: // NODE STATE // Entire netlist: @@ -408,21 +400,19 @@ private: void consumedMark(); void consumedMarkRecurse(GateEitherVertex* vertexp); void consumedMove(); - void replaceAssigns(); void dedupe(); void mergeAssigns(); void decomposeClkVectors(); // VISITORS - virtual void visit(AstNetlist* nodep) override { + void visit(AstNetlist* nodep) override { iterateChildren(nodep); - // if (debug() > 6) m_graph.dump(); - if (debug() > 6) m_graph.dumpDotFilePrefixed("gate_pre"); + if (dumpGraph() >= 3) m_graph.dumpDotFilePrefixed("gate_pre"); warnSignals(); // Before loss of sync/async pointers // Decompose clock vectors -- need to do this before removing redundant edges decomposeClkVectors(); m_graph.removeRedundantEdgesSum(&V3GraphEdge::followAlwaysTrue); - m_graph.dumpDotFilePrefixed("gate_simp"); + if (dumpGraph() >= 6) m_graph.dumpDotFilePrefixed("gate_simp"); // Find gate interconnect and optimize m_graph.userClearVertices(); // vertex->user(): bool. Indicates we've set it as consumed // Get rid of buffers first, @@ -434,20 +424,19 @@ private: // Remove redundant logic if (v3Global.opt.fDedupe()) { dedupe(); - if (debug() >= 6) m_graph.dumpDotFilePrefixed("gate_dedup"); + if (dumpGraph() >= 6) m_graph.dumpDotFilePrefixed("gate_dedup"); } if (v3Global.opt.fAssemble()) { mergeAssigns(); - if (debug() >= 6) m_graph.dumpDotFilePrefixed("gate_assm"); + if (dumpGraph() >= 6) m_graph.dumpDotFilePrefixed("gate_assm"); } // Consumption warnings consumedMark(); - m_graph.dumpDotFilePrefixed("gate_opt"); + if (dumpGraph() >= 3) m_graph.dumpDotFilePrefixed("gate_opt"); // Rewrite assignments consumedMove(); - replaceAssigns(); } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { VL_RESTORER(m_modp); { m_modp = nodep; @@ -455,14 +444,14 @@ private: iterateChildren(nodep); } } - virtual void visit(AstScope* nodep) override { + void visit(AstScope* nodep) override { UINFO(4, " SCOPE " << nodep << endl); m_scopep = nodep; m_logicVertexp = nullptr; iterateChildren(nodep); m_scopep = nullptr; } - virtual void visit(AstActive* nodep) override { + void visit(AstActive* nodep) override { // Create required blocks and add to module UINFO(4, " BLOCK " << nodep << endl); m_activeReducible = !(nodep->hasClocked()); // Seq logic outputs aren't reducible @@ -473,7 +462,7 @@ private: m_activep = nullptr; m_activeReducible = true; } - virtual void visit(AstNodeVarRef* nodep) override { + void visit(AstNodeVarRef* nodep) override { if (m_scopep) { UASSERT_OBJ(m_logicVertexp, nodep, "Var ref not under a logic block"); AstVarScope* const varscp = nodep->varScopep(); @@ -501,17 +490,17 @@ private: } } } - virtual void visit(AstAlwaysPublic* nodep) override { + void visit(AstAlwaysPublic* nodep) override { VL_RESTORER(m_inSlow); { m_inSlow = true; iterateNewStmt(nodep, "AlwaysPublic", nullptr); } } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { iterateNewStmt(nodep, "User C Function", "User C Function"); } - virtual void visit(AstSenItem* nodep) override { + void visit(AstSenItem* nodep) override { m_inSenItem = true; if (m_logicVertexp) { // Already under logic; presumably a SenGate iterateChildren(nodep); @@ -520,7 +509,7 @@ private: } m_inSenItem = false; } - virtual void visit(AstNodeProcedure* nodep) override { + void visit(AstNodeProcedure* nodep) override { VL_RESTORER(m_inSlow); { m_inSlow = VN_IS(nodep, Initial) || VN_IS(nodep, Final); @@ -528,23 +517,23 @@ private: nullptr); } } - virtual void visit(AstAssignAlias* nodep) override { // + void visit(AstAssignAlias* nodep) override { // iterateNewStmt(nodep, nullptr, nullptr); } - virtual void visit(AstAssignW* nodep) override { // + void visit(AstAssignW* nodep) override { // iterateNewStmt(nodep, nullptr, nullptr); } - virtual void visit(AstCoverToggle* nodep) override { + void visit(AstCoverToggle* nodep) override { iterateNewStmt(nodep, "CoverToggle", "CoverToggle"); } - virtual void visit(AstTraceDecl* nodep) override { + void visit(AstTraceDecl* nodep) override { VL_RESTORER(m_inSlow); { m_inSlow = true; iterateNewStmt(nodep, "Tracing", "Tracing"); } } - virtual void visit(AstConcat* nodep) override { + void visit(AstConcat* nodep) override { UASSERT_OBJ(!(VN_IS(nodep->backp(), NodeAssign) && VN_AS(nodep->backp(), NodeAssign)->lhsp() == nodep), nodep, "Concat on LHS of assignment; V3Const should have deleted it"); @@ -552,7 +541,7 @@ private: } //-------------------- - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { iterateChildren(nodep); if (nodep->isOutputter() && m_logicVertexp) m_logicVertexp->setConsumed("outputter"); } @@ -560,7 +549,7 @@ private: public: // CONSTRUCTORS explicit GateVisitor(AstNode* nodep) { iterate(nodep); } - virtual ~GateVisitor() override { + ~GateVisitor() override { V3Stats::addStat("Optimizations, Gate sigs deleted", m_statSigs); V3Stats::addStat("Optimizations, Gate inputs replaced", m_statRefs); V3Stats::addStat("Optimizations, Gate sigs deduped", m_statDedupLogic); @@ -654,14 +643,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) { while (V3GraphEdge* const edgep = vvertexp->inBeginp()) { VL_DO_DANGLING(edgep->unlinkDelete(), edgep); } - // Clone tree so we remember it for tracing, and keep the pointer - // to the "ALWAYS" part of the tree as part of this statement - // That way if a later signal optimization that - // retained a pointer to the always can - // optimize it further - VL_DO_DANGLING(vvertexp->varScp()->valuep(logicp->unlinkFrBack()), logicp); - // Mark the vertex so we don't mark it as being - // unconsumed in the next step + // Mark the vertex so we don't mark it as being unconsumed in the next step vvertexp->user(true); logicVertexp->user(true); } @@ -683,7 +665,7 @@ bool GateVisitor::elimLogicOkOutputs(GateLogicVertex* consumeVertexp, varscopes.insert(vscp); } for (V3GraphEdge* edgep = consumeVertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { - const GateVarVertex* const consVVertexp = dynamic_cast(edgep->top()); + const GateVarVertex* const consVVertexp = static_cast(edgep->top()); AstVarScope* const vscp = consVVertexp->varScp(); if (varscopes.find(vscp) != varscopes.end()) { UINFO(9, " Block-unopt, insertion generates input vscp " << vscp << endl); @@ -693,45 +675,6 @@ bool GateVisitor::elimLogicOkOutputs(GateLogicVertex* consumeVertexp, return true; } -void GateVisitor::replaceAssigns() { - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { - if (const GateVarVertex* const vvertexp = dynamic_cast(itp)) { - // Take the Comments/assigns that were moved to the VarScope and change them to a - // simple value assignment - const AstVarScope* const vscp = vvertexp->varScp(); - if (vscp->valuep() && !VN_IS(vscp->valuep(), NodeMath)) { - // if (debug() > 9) vscp->dumpTree(cout, "-vscPre: "); - while (AstNode* delp = VN_CAST(vscp->valuep(), Comment)) { - VL_DO_DANGLING(delp->unlinkFrBack()->deleteTree(), delp); - } - if (AstInitial* const delp = VN_CAST(vscp->valuep(), Initial)) { - AstNode* const bodyp = delp->bodysp(); - bodyp->unlinkFrBackWithNext(); - delp->replaceWith(bodyp); - VL_DO_DANGLING(delp->deleteTree(), delp); - } - if (AstAlways* const delp = VN_CAST(vscp->valuep(), Always)) { - AstNode* const bodyp = delp->bodysp(); - bodyp->unlinkFrBackWithNext(); - delp->replaceWith(bodyp); - VL_DO_DANGLING(delp->deleteTree(), delp); - } - if (AstNodeAssign* const delp = VN_CAST(vscp->valuep(), NodeAssign)) { - AstNode* const rhsp = delp->rhsp(); - rhsp->unlinkFrBack(); - delp->replaceWith(rhsp); - VL_DO_DANGLING(delp->deleteTree(), delp); - } - // if (debug() > 9) {vscp->dumpTree(cout, "-vscDone: "); cout<valuep(), NodeMath) || vscp->valuep()->nextp()) { - vscp->dumpTree(std::cerr, "vscStrange: "); - vscp->v3fatalSrc("Value of varscope not mathematical"); - } - } - } - } -} - //---------------------------------------------------------------------- void GateVisitor::consumedMark() { @@ -764,8 +707,8 @@ void GateVisitor::consumedMove() { if (!vvertexp->consumed() && !vvertexp->user()) { UINFO(8, "Unconsumed " << vvertexp->varScp() << endl); } - } - if (const GateLogicVertex* const lvertexp = dynamic_cast(vertexp)) { + } else { + const GateLogicVertex* const lvertexp = static_cast(vertexp); AstNode* const nodep = lvertexp->nodep(); const AstActive* const oldactp = lvertexp->activep(); // nullptr under cfunc if (!lvertexp->consumed() && oldactp) { @@ -830,8 +773,6 @@ private: V3DupFinder m_dupFinder; // Duplicate finder for rhs of assigns std::unordered_set m_nodeDeleteds; // Any node in this hash was deleted - VL_DEBUG_FUNC; // Declare debug() - bool same(AstNode* node1p, AstNode* node2p) { // Regarding the complexity of this funcition 'same': // Applying this comparison function to a a set of n trees pairwise is O(n^2) in the @@ -858,7 +799,7 @@ private: public: GateDedupeHash() = default; - virtual ~GateDedupeHash() override { + ~GateDedupeHash() override { if (v3Global.opt.debugCheck()) check(); } @@ -884,7 +825,7 @@ public: } // Callback from V3DupFinder::findDuplicate - virtual bool isSame(AstNode* node1p, AstNode* node2p) override { + bool isSame(AstNode* node1p, AstNode* node2p) override { // Assignment may have been hashReplaced, if so consider non-match (effectively removed) if (isReplaced(node1p) || isReplaced(node2p)) { // UINFO(9, "isSame hit on replaced "<<(void*)node1p<<" "<<(void*)node2p<bodysp()); + iterateAndNextNull(alwaysp->stmtsp()); } else { m_dedupable = false; } @@ -981,28 +922,28 @@ private: // always @(...) // if (...) // foo = ...; // or foo <= ...; - virtual void visit(AstNodeIf* ifp) override { + void visit(AstNodeIf* ifp) override { if (m_dedupable) { if (m_always && !m_ifCondp && !ifp->elsesp()) { // we're under an always, this is the first IF, and there's no else m_ifCondp = ifp->condp(); - iterateAndNextNull(ifp->ifsp()); + iterateAndNextNull(ifp->thensp()); } else { m_dedupable = false; } } } - virtual void visit(AstComment*) override {} // NOP + void visit(AstComment*) override {} // NOP //-------------------- - virtual void visit(AstNode*) override { // + void visit(AstNode*) override { // m_dedupable = false; } public: // CONSTRUCTORS GateDedupeVarVisitor() = default; - virtual ~GateDedupeVarVisitor() override = default; + ~GateDedupeVarVisitor() override = default; // PUBLIC METHODS AstNodeVarRef* findDupe(AstNode* nodep, AstVarScope* consumerVarScopep, AstActive* activep) { m_assignp = nullptr; @@ -1033,11 +974,18 @@ static void eliminate(AstNode* logicp, const std::unordered_map& substitutions, GateDedupeVarVisitor* varVisp) { - const std::function visit - = [&substitutions, &visit, varVisp](AstNodeVarRef* nodep) -> void { + // Recursion filter holding already replaced variables + std::unordered_set replaced(substitutions.size() * 2); + + const std::function visit = [&, varVisp](AstNodeVarRef* nodep) -> void { // See if this variable has a substitution - const auto& it = substitutions.find(nodep->varScopep()); + AstVarScope* const vscp = nodep->varScopep(); + const auto& it = substitutions.find(vscp); if (it == substitutions.end()) return; + + // Do not substitute circular logic + if (!replaced.insert(vscp).second) return; + AstNode* const substp = it->second; // Substitute in the new tree @@ -1064,6 +1012,9 @@ static void eliminate(AstNode* logicp, VL_DO_DANGLING(nodep->deleteTree(), nodep); // Recursively substitute the new tree newp->foreach(visit); + + // Remove from recursion filter + replaced.erase(vscp); }; logicp->foreach(visit); @@ -1081,17 +1032,17 @@ private: GateDedupeVarVisitor m_varVisitor; // Looks for a dupe of the logic int m_depth = 0; // Iteration depth - virtual VNUser visit(GateVarVertex* vvertexp, VNUser) override { + VNUser visit(GateVarVertex* vvertexp, VNUser) override { // Check that we haven't been here before if (m_depth > GATE_DEDUP_MAX_DEPTH) - return VNUser(0); // Break loops; before user2 set so hit this vertex later - if (vvertexp->varScp()->user2()) return VNUser(0); + return VNUser{0}; // Break loops; before user2 set so hit this vertex later + if (vvertexp->varScp()->user2()) return VNUser{0}; vvertexp->varScp()->user2(true); m_depth++; if (vvertexp->inSize1()) { AstNodeVarRef* const dupVarRefp = static_cast( - vvertexp->iterateInEdges(*this, VNUser(vvertexp)).toNodep()); + vvertexp->iterateInEdges(*this, VNUser{vvertexp}).toNodep()); if (dupVarRefp) { // visit(GateLogicVertex*...) returned match const V3GraphEdge* edgep = vvertexp->inBeginp(); GateLogicVertex* const lvertexp = static_cast(edgep->fromp()); @@ -1108,9 +1059,8 @@ private: // Replace all of this varvertex's consumers with dupVarRefp for (V3GraphEdge* outedgep = vvertexp->outBeginp(); outedgep;) { const GateLogicVertex* const consumeVertexp - = dynamic_cast(outedgep->top()); + = static_cast(outedgep->top()); AstNode* const consumerp = consumeVertexp->nodep(); - // if (debug() >= 9) m_graphp->dumpDotFilePrefixed("gate_preelim"); UINFO(9, "elim src vtx" << lvertexp << " node " << lvertexp->nodep() << endl); UINFO(9, @@ -1132,23 +1082,18 @@ private: while (V3GraphEdge* const inedgep = vvertexp->inBeginp()) { VL_DO_DANGLING(inedgep->unlinkDelete(), inedgep); } - // replaceAssigns() does the deleteTree on lvertexNodep in a later step - AstNode* lvertexNodep = lvertexp->nodep(); - lvertexNodep->unlinkFrBack(); - vvertexp->varScp()->valuep(lvertexNodep); - lvertexNodep = nullptr; vvertexp->user(true); lvertexp->user(true); } } } m_depth--; - return VNUser(0); + return VNUser{0}; } // Given iterated logic, starting at vu which was consumer's GateVarVertex // Returns a varref that has the same logic input; or nullptr if none - virtual VNUser visit(GateLogicVertex* lvertexp, VNUser vu) override { + VNUser visit(GateLogicVertex* lvertexp, VNUser vu) override { lvertexp->iterateInEdges(*this); const GateVarVertex* const consumerVvertexpp @@ -1161,9 +1106,9 @@ private: // different generated clocks will never compare as equal, even if the // generated clocks are deduped into one clock. AstActive* const activep = lvertexp->activep(); - return VNUser(m_varVisitor.findDupe(nodep, consumerVarScopep, activep)); + return VNUser{m_varVisitor.findDupe(nodep, consumerVarScopep, activep)}; } - return VNUser(0); + return VNUser{0}; } public: @@ -1228,7 +1173,7 @@ private: } } - virtual VNUser visit(GateVarVertex* vvertexp, VNUser) override { + VNUser visit(GateVarVertex* vvertexp, VNUser) override { for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep;) { V3GraphEdge* oldedgep = edgep; edgep = edgep->inNextp(); // for recursive since the edge could be deleted @@ -1283,7 +1228,7 @@ private: V3GraphEdge* oedgep = ledgep; ledgep = ledgep->inNextp(); GateEitherVertex* const fromvp - = dynamic_cast(oedgep->fromp()); + = static_cast(oedgep->fromp()); new V3GraphEdge(m_graphp, fromvp, m_logicvp, 1); VL_DO_DANGLING(oedgep->unlinkDelete(), oedgep); } @@ -1300,10 +1245,10 @@ private: } } } - return VNUser(0); + return VNUser{0}; } - virtual VNUser visit(GateLogicVertex*, VNUser) override { // - return VNUser(0); + VNUser visit(GateLogicVertex*, VNUser) override { // + return VNUser{0}; } public: @@ -1331,7 +1276,7 @@ void GateVisitor::mergeAssigns() { //###################################################################### // Find a var's offset in a concatenation -class GateConcatVisitor final : public GateBaseVisitor { +class GateConcatVisitor final : public VNVisitor { private: // STATE const AstVarScope* m_vscp = nullptr; // Varscope we're trying to find @@ -1340,7 +1285,7 @@ private: bool m_found = false; // Offset found // VISITORS - virtual void visit(AstNodeVarRef* nodep) override { + void visit(AstNodeVarRef* nodep) override { UINFO(9, "CLK DECOMP Concat search var (off = " << m_offset << ") - " << nodep << endl); if (nodep->varScopep() == m_vscp && !nodep->user2() && !m_found) { // A concatenation may use the same var multiple times @@ -1352,18 +1297,18 @@ private: } m_offset += nodep->dtypep()->width(); } - virtual void visit(AstConcat* nodep) override { + void visit(AstConcat* nodep) override { UINFO(9, "CLK DECOMP Concat search (off = " << m_offset << ") - " << nodep << endl); iterate(nodep->rhsp()); iterate(nodep->lhsp()); } //-------------------- - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS GateConcatVisitor() = default; - virtual ~GateConcatVisitor() override = default; + ~GateConcatVisitor() override = default; // PUBLIC METHODS bool concatOffset(AstConcat* concatp, AstVarScope* vscp, int& offsetr) { m_vscp = vscp; @@ -1403,10 +1348,10 @@ private: int m_total_seen_clk_vectors = 0; int m_total_decomposed_clk_vectors = 0; - virtual VNUser visit(GateVarVertex* vvertexp, VNUser vu) override { + VNUser visit(GateVarVertex* vvertexp, VNUser vu) override { // Check that we haven't been here before AstVarScope* const vsp = vvertexp->varScp(); - if (vsp->user2SetOnce()) return VNUser(0); + if (vsp->user2SetOnce()) return VNUser{0}; UINFO(9, "CLK DECOMP Var - " << vvertexp << " : " << vsp << endl); if (vsp->varp()->width() > 1) { m_seen_clk_vectors++; @@ -1414,13 +1359,13 @@ private: } const GateClkDecompState* const currState = reinterpret_cast(vu.c()); GateClkDecompState nextState(currState->m_offset, vsp); - vvertexp->iterateCurrentOutEdges(*this, VNUser(&nextState)); + vvertexp->iterateCurrentOutEdges(*this, VNUser{&nextState}); if (vsp->varp()->width() > 1) --m_seen_clk_vectors; vsp->user2(false); - return VNUser(0); // Unused + return VNUser{0}; // Unused } - virtual VNUser visit(GateLogicVertex* lvertexp, VNUser vu) override { + VNUser visit(GateLogicVertex* lvertexp, VNUser vu) override { const GateClkDecompState* const currState = reinterpret_cast(vu.c()); int clk_offset = currState->m_offset; if (const AstAssignW* const assignp = VN_CAST(lvertexp->nodep(), AssignW)) { @@ -1433,37 +1378,37 @@ private: UINFO(9, "CLK DECOMP Sel [ " << rselp->msbConst() << " : " << rselp->lsbConst() << " ] dropped clock (" << clk_offset << ")" << endl); - return VNUser(0); + return VNUser{0}; } clk_offset -= rselp->lsbConst(); } else { - return VNUser(0); + return VNUser{0}; } } else if (AstConcat* const catp = VN_CAST(assignp->rhsp(), Concat)) { UINFO(9, "CLK DECOMP Concat searching - " << assignp->lhsp() << endl); int concat_offset; if (!m_concat_visitor.concatOffset(catp, currState->m_last_vsp, concat_offset /*ref*/)) { - return VNUser(0); + return VNUser{0}; } clk_offset += concat_offset; } else if (VN_IS(assignp->rhsp(), VarRef)) { UINFO(9, "CLK DECOMP VarRef searching - " << assignp->lhsp() << endl); } else { - return VNUser(0); + return VNUser{0}; } // LHS if (const AstSel* const lselp = VN_CAST(assignp->lhsp(), Sel)) { if (VN_IS(lselp->lsbp(), Const) && VN_IS(lselp->widthp(), Const)) { clk_offset += lselp->lsbConst(); } else { - return VNUser(0); + return VNUser{0}; } } else if (const AstVarRef* const vrp = VN_CAST(assignp->lhsp(), VarRef)) { if (vrp->dtypep()->width() == 1 && m_seen_clk_vectors) { if (clk_offset != 0) { UINFO(9, "Should only make it here with clk_offset = 0" << endl); - return VNUser(0); + return VNUser{0}; } UINFO(9, "CLK DECOMP Connecting - " << assignp->lhsp() << endl); UINFO(9, " to - " << m_clk_vsp << endl); @@ -1476,18 +1421,18 @@ private: m_total_decomposed_clk_vectors++; } } else { - return VNUser(0); + return VNUser{0}; } GateClkDecompState nextState(clk_offset, currState->m_last_vsp); - return lvertexp->iterateCurrentOutEdges(*this, VNUser(&nextState)); + return lvertexp->iterateCurrentOutEdges(*this, VNUser{&nextState}); } - return VNUser(0); + return VNUser{0}; } public: explicit GateClkDecompGraphVisitor(V3Graph* graphp) : GateGraphBaseVisitor{graphp} {} - virtual ~GateClkDecompGraphVisitor() override { + ~GateClkDecompGraphVisitor() override { V3Stats::addStat("Optimizations, Clocker seen vectors", m_total_seen_clk_vectors); V3Stats::addStat("Optimizations, Clocker decomposed vectors", m_total_decomposed_clk_vectors); @@ -1498,7 +1443,7 @@ public: m_clk_vsp = vvertexp->varScp(); m_clk_vvertexp = vvertexp; GateClkDecompState nextState(0, m_clk_vsp); - vvertexp->accept(*this, VNUser(&nextState)); + vvertexp->accept(*this, VNUser{&nextState}); } }; @@ -1527,16 +1472,5 @@ void GateVisitor::decomposeClkVectors() { void V3Gate::gateAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { const GateVisitor visitor{nodep}; } // Destruct before checking - - nodep->foreach([](AstVarScope* nodep) { - if (AstNodeAssign* const assp = VN_CAST(nodep->valuep(), NodeAssign)) { - UINFO(5, " Removeassign " << assp << endl); - AstNode* const valuep = assp->rhsp(); - valuep->unlinkFrBack(); - assp->replaceWith(valuep); - VL_DO_DANGLING(assp->deleteTree(), assp); - } - }); - - V3Global::dumpCheckGlobalTree("gate", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("gate", 0, dumpTree() >= 3); } diff --git a/src/V3GenClk.cpp b/src/V3GenClk.cpp index dd3985b6f..d4b507238 100644 --- a/src/V3GenClk.cpp +++ b/src/V3GenClk.cpp @@ -27,18 +27,12 @@ #include "V3Ast.h" #include "V3Global.h" -//###################################################################### -// GenClk state, as a visitor of each AstNode - -class GenClkBaseVisitor VL_NOT_FINAL : public VNVisitor { -protected: - VL_DEBUG_FUNC; // Declare debug() -}; +VL_DEFINE_DEBUG_FUNCTIONS; //###################################################################### // GenClk Read -class GenClkRenameVisitor final : public GenClkBaseVisitor { +class GenClkRenameVisitor final : public VNVisitor { private: // NODE STATE // Cleared on top scope @@ -76,13 +70,13 @@ private: // ASSIGN(VARREF(inpclk), VARREF(var)) AstVar* const newvarp = new AstVar(varp->fileline(), VVarType::MODULETEMP, newvarname, varp); - m_topModp->addStmtp(newvarp); + m_topModp->addStmtsp(newvarp); AstVarScope* const newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp); - m_scopetopp->addVarp(newvscp); + m_scopetopp->addVarsp(newvscp); AstAssign* const asninitp = new AstAssign( vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, VAccess::WRITE), new AstVarRef(vscp->fileline(), vscp, VAccess::READ)); - m_scopetopp->addFinalClkp(asninitp); + m_scopetopp->addFinalClksp(asninitp); // vscp->user2p(newvscp); } @@ -90,7 +84,7 @@ private: } // VISITORS - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { // Consumption/generation of a variable, if (m_activep && !nodep->user3SetOnce()) { AstVarScope* const vscp = nodep->varScopep(); @@ -105,14 +99,14 @@ private: } } } - virtual void visit(AstActive* nodep) override { + void visit(AstActive* nodep) override { m_activep = nodep; iterate(nodep->sensesp()); m_activep = nullptr; } //----- - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -120,13 +114,13 @@ public: : m_topModp{topModp} { iterate(nodep); } - virtual ~GenClkRenameVisitor() override = default; + ~GenClkRenameVisitor() override = default; }; //###################################################################### // GenClk Read -class GenClkReadVisitor final : public GenClkBaseVisitor { +class GenClkReadVisitor final : public VNVisitor { private: // NODE STATE // Cleared on top scope @@ -139,7 +133,7 @@ private: AstNodeModule* m_topModp = nullptr; // Top module // VISITORS - virtual void visit(AstTopScope* nodep) override { + void visit(AstTopScope* nodep) override { { const VNUser1InUse user1InUse; iterateChildren(nodep); @@ -148,14 +142,14 @@ private: // See rename, it does some AstNode::userClearTree()'s GenClkRenameVisitor{nodep, m_topModp}; } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { // Only track the top scopes, not lower level functions if (nodep->isTop()) { m_topModp = nodep; iterateChildren(nodep); } } - virtual void visit(AstNodeCCall* nodep) override { + void visit(AstNodeCCall* nodep) override { iterateChildren(nodep); if (!nodep->funcp()->entryPoint()) { // Enter the function and trace it @@ -163,7 +157,7 @@ private: iterate(nodep->funcp()); } } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { if (!m_tracingCall && !nodep->entryPoint()) { // Only consider logic within a CFunc when looking // at the call to it, and not when scanning whatever @@ -175,7 +169,7 @@ private: } //---- - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { // Consumption/generation of a variable, AstVarScope* const vscp = nodep->varScopep(); UASSERT_OBJ(vscp, nodep, "Scope not assigned"); @@ -190,13 +184,13 @@ private: vscp->circular(true); } } - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { // UINFO(8, "ASS " << nodep << endl); m_assignp = nodep; iterateChildren(nodep); m_assignp = nullptr; } - virtual void visit(AstActive* nodep) override { + void visit(AstActive* nodep) override { UINFO(8, "ACTIVE " << nodep << endl); m_activep = nodep; UASSERT_OBJ(nodep->sensesp(), nodep, "Unlinked"); @@ -206,13 +200,13 @@ private: } //----- - virtual void visit(AstVar*) override {} // Don't want varrefs under it - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstVar*) override {} // Don't want varrefs under it + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit GenClkReadVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~GenClkReadVisitor() override = default; + ~GenClkReadVisitor() override = default; }; //###################################################################### @@ -221,5 +215,5 @@ public: void V3GenClk::genClkAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { GenClkReadVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("genclk", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("genclk", 0, dumpTree() >= 3); } diff --git a/src/V3Global.h b/src/V3Global.h index 1341332f5..0a50e97b6 100644 --- a/src/V3Global.h +++ b/src/V3Global.h @@ -70,19 +70,19 @@ public: VWidthMinUsage() : m_e{LINT_WIDTH} {} // cppcheck-suppress noExplicitConstructor - VWidthMinUsage(en _e) + constexpr VWidthMinUsage(en _e) : m_e{_e} {} explicit VWidthMinUsage(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } }; -inline bool operator==(const VWidthMinUsage& lhs, const VWidthMinUsage& rhs) { +constexpr bool operator==(const VWidthMinUsage& lhs, const VWidthMinUsage& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VWidthMinUsage& lhs, VWidthMinUsage::en rhs) { +constexpr bool operator==(const VWidthMinUsage& lhs, VWidthMinUsage::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VWidthMinUsage::en lhs, const VWidthMinUsage& rhs) { +constexpr bool operator==(VWidthMinUsage::en lhs, const VWidthMinUsage& rhs) { return lhs == rhs.m_e; } diff --git a/src/V3Graph.cpp b/src/V3Graph.cpp index fe0be1cf6..faffb7b41 100644 --- a/src/V3Graph.cpp +++ b/src/V3Graph.cpp @@ -28,8 +28,7 @@ #include #include -int V3Graph::s_debug = 0; -int V3Graph::debug() { return std::max(V3Error::debugDefault(), s_debug); } +VL_DEFINE_DEBUG_FUNCTIONS; //###################################################################### //###################################################################### @@ -312,9 +311,7 @@ void V3Graph::dumpEdge(std::ostream& os, V3GraphVertex* vertexp, V3GraphEdge* ed } void V3Graph::dumpDotFilePrefixed(const string& nameComment, bool colorAsSubgraph) const { - if (v3Global.opt.dumpTree()) { - dumpDotFile(v3Global.debugFilename(nameComment) + ".dot", colorAsSubgraph); - } + dumpDotFile(v3Global.debugFilename(nameComment) + ".dot", colorAsSubgraph); } //! Variant of dumpDotFilePrefixed without --dump option check diff --git a/src/V3Graph.h b/src/V3Graph.h index a18fb5dfc..0de50222a 100644 --- a/src/V3Graph.h +++ b/src/V3Graph.h @@ -54,14 +54,14 @@ public: // // an array dimension or loop bound. }; enum en m_e; - inline GraphWay() + GraphWay() : m_e{FORWARD} {} // cppcheck-suppress noExplicitConstructor - inline constexpr GraphWay(en _e) + constexpr GraphWay(en _e) : m_e{_e} {} - explicit inline constexpr GraphWay(int _e) + explicit constexpr GraphWay(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } const char* ascii() const { static const char* const names[] = {"FORWARD", "REVERSE"}; return names[m_e]; @@ -71,9 +71,9 @@ public: constexpr bool forward() const { return m_e == FORWARD; } constexpr bool reverse() const { return m_e != FORWARD; } }; -inline bool operator==(const GraphWay& lhs, const GraphWay& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const GraphWay& lhs, GraphWay::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(GraphWay::en lhs, const GraphWay& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const GraphWay& lhs, const GraphWay& rhs) { return lhs.m_e == rhs.m_e; } +constexpr bool operator==(const GraphWay& lhs, GraphWay::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(GraphWay::en lhs, const GraphWay& rhs) { return lhs == rhs.m_e; } //============================================================================ @@ -81,7 +81,6 @@ class V3Graph VL_NOT_FINAL { private: // MEMBERS V3List m_vertices; // All vertices - static int s_debug; protected: friend class V3GraphVertex; @@ -92,12 +91,10 @@ protected: void dumpEdge(std::ostream& os, V3GraphVertex* vertexp, V3GraphEdge* edgep); void verticesUnlink() { m_vertices.reset(); } // ACCESSORS - static int debug(); public: V3Graph(); virtual ~V3Graph(); - static void debug(int level) { s_debug = level; } virtual string dotRankDir() const { return "TB"; } // rankdir for dot plotting // METHODS diff --git a/src/V3GraphAcyc.cpp b/src/V3GraphAcyc.cpp index 0df758ed1..016c6930b 100644 --- a/src/V3GraphAcyc.cpp +++ b/src/V3GraphAcyc.cpp @@ -24,6 +24,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### //###################################################################### // Algorithms - acyclic @@ -42,13 +44,13 @@ public: GraphAcycVertex(V3Graph* graphp, V3GraphVertex* origVertexp) : V3GraphVertex{graphp} , m_origVertexp{origVertexp} {} - virtual ~GraphAcycVertex() override = default; + ~GraphAcycVertex() override = default; V3GraphVertex* origVertexp() const { return m_origVertexp; } void setDelete() { m_deleted = true; } bool isDelete() const { return m_deleted; } - virtual string name() const override { return m_origVertexp->name(); } - virtual string dotColor() const override { return m_origVertexp->dotColor(); } - virtual FileLine* fileline() const override { return m_origVertexp->fileline(); } + string name() const override { return m_origVertexp->name(); } + string dotColor() const override { return m_origVertexp->dotColor(); } + FileLine* fileline() const override { return m_origVertexp->fileline(); } }; //-------------------------------------------------------------------- @@ -67,11 +69,9 @@ public: GraphAcycEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, bool cutable = false) : V3GraphEdge{graphp, fromp, top, weight, cutable} {} - virtual ~GraphAcycEdge() override = default; + ~GraphAcycEdge() override = default; // yellow=we might still cut it, else oldEdge: yellowGreen=made uncutable, red=uncutable - virtual string dotColor() const override { - return (cutable() ? "yellow" : origEdgep()->dotColor()); - } + string dotColor() const override { return (cutable() ? "yellow" : origEdgep()->dotColor()); } }; //-------------------------------------------------------------------- @@ -106,8 +106,6 @@ private: m_origEdgeFuncp; // Function that says we follow this edge (in original graph) uint32_t m_placeStep = 0; // Number that user() must be equal to to indicate processing - static int debug() { return V3Graph::debug(); } - // METHODS void buildGraph(V3Graph* origGraphp); void buildGraphIterate(V3GraphVertex* overtexp, GraphAcycVertex* avertexp); @@ -123,7 +121,7 @@ private: void placeTryEdge(V3GraphEdge* edgep); bool placeIterate(GraphAcycVertex* vertexp, uint32_t currentRank); - inline bool origFollowEdge(V3GraphEdge* edgep) { + bool origFollowEdge(V3GraphEdge* edgep) { return (edgep->weight() && (m_origEdgeFuncp)(edgep)); } V3GraphEdge* edgeFromEdge(V3GraphEdge* oldedgep, V3GraphVertex* fromp, V3GraphVertex* top) { @@ -546,28 +544,28 @@ void GraphAcyc::main() { // edges (and thus can't represent loops - if we did the unbreakable // marking right, anyways) buildGraph(m_origGraphp); - if (debug() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_pre"); + if (dumpGraph() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_pre"); // Perform simple optimizations before any cuttings simplify(false); - if (debug() >= 5) m_breakGraph.dumpDotFilePrefixed("acyc_simp"); + if (dumpGraph() >= 5) m_breakGraph.dumpDotFilePrefixed("acyc_simp"); UINFO(4, " Cutting trivial loops\n"); simplify(true); - if (debug() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_mid"); + if (dumpGraph() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_mid"); UINFO(4, " Ranking\n"); m_breakGraph.rank(&V3GraphEdge::followNotCutable); - if (debug() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_rank"); + if (dumpGraph() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_rank"); UINFO(4, " Placement\n"); place(); - if (debug() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_place"); + if (dumpGraph() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_place"); UINFO(4, " Final Ranking\n"); // Only needed to assert there are no loops in completed graph m_breakGraph.rank(&V3GraphEdge::followAlwaysTrue); - if (debug() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_done"); + if (dumpGraph() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_done"); } void V3Graph::acyclic(V3EdgeFuncP edgeFuncp) { diff --git a/src/V3GraphAlg.cpp b/src/V3GraphAlg.cpp index c5e7dcec9..b74de1351 100644 --- a/src/V3GraphAlg.cpp +++ b/src/V3GraphAlg.cpp @@ -27,6 +27,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### //###################################################################### // Algorithms - weakly connected components @@ -120,7 +122,6 @@ public: } private: - VL_DEBUG_FUNC; // Declare debug() VL_UNCOPYABLE(GraphAlgRemoveTransitiveEdges); }; @@ -177,7 +178,10 @@ private: std::vector m_callTrace; // List of everything we hit processing so far void main() { - // Use Tarjan's algorithm to find the strongly connected subgraphs. + // Use Pearce's algorithm to color the strongly connected components. For reference see + // "An Improved Algorithm for Finding the Strongly Connected Components of a Directed + // Graph", David J.Pearce, 2005 + // // Node State: // Vertex::user // DFS number indicating possible root of subtree, 0=not iterated // Vertex::color // Output subtree number (fully processed) diff --git a/src/V3GraphAlg.h b/src/V3GraphAlg.h index 2cc4ce9b5..6441b2cca 100644 --- a/src/V3GraphAlg.h +++ b/src/V3GraphAlg.h @@ -38,9 +38,7 @@ protected: , m_edgeFuncp{edgeFuncp} {} ~GraphAlg() = default; // METHODS - inline bool followEdge(V3GraphEdge* edgep) { - return (edgep->weight() && (m_edgeFuncp)(edgep)); - } + bool followEdge(V3GraphEdge* edgep) { return (edgep->weight() && (m_edgeFuncp)(edgep)); } }; //============================================================================ diff --git a/src/V3GraphPathChecker.h b/src/V3GraphPathChecker.h index 06be17d4f..b919c7869 100644 --- a/src/V3GraphPathChecker.h +++ b/src/V3GraphPathChecker.h @@ -56,7 +56,6 @@ private: void initHalfCriticalPaths(GraphWay way, bool checkOnly); void incGeneration() { ++m_generation; } - VL_DEBUG_FUNC; // Declare debug() VL_UNCOPYABLE(GraphPathChecker); }; diff --git a/src/V3GraphTest.cpp b/src/V3GraphTest.cpp index 757c7ff70..3fdb8dfe7 100644 --- a/src/V3GraphTest.cpp +++ b/src/V3GraphTest.cpp @@ -20,6 +20,8 @@ #include "V3Global.h" #include "V3Graph.h" +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### //###################################################################### // Test class @@ -34,14 +36,14 @@ protected: virtual string name() = 0; // Name of the test // Utilities - void dump() { - if (debug() >= 9) m_graph.dumpDotFilePrefixed("v3graphtest_" + name()); + void dumpSelf() { + if (dumpGraph() >= 9) m_graph.dumpDotFilePrefixed("v3graphtest_" + name()); } public: V3GraphTest() = default; virtual ~V3GraphTest() = default; - VL_DEBUG_FUNC; // Declare debug() + void run() { runTest(); } }; @@ -56,18 +58,18 @@ public: V3GraphTestVertex(V3Graph* graphp, const string& name) : V3GraphVertex{graphp} , m_name{name} {} - virtual ~V3GraphTestVertex() override = default; + ~V3GraphTestVertex() override = default; // ACCESSORS - virtual string name() const override { return m_name; } + string name() const override { return m_name; } }; class V3GraphTestVarVertex final : public V3GraphTestVertex { public: V3GraphTestVarVertex(V3Graph* graphp, const string& name) : V3GraphTestVertex{graphp, name} {} - virtual ~V3GraphTestVarVertex() override = default; + ~V3GraphTestVarVertex() override = default; // ACCESSORS - virtual string dotColor() const override { return "blue"; } + string dotColor() const override { return "blue"; } }; //###################################################################### @@ -76,8 +78,8 @@ public: class V3GraphTestStrong final : public V3GraphTest { public: - virtual string name() override { return "strong"; } - virtual void runTest() override { + string name() override { return "strong"; } + void runTest() override { V3Graph* gp = &m_graph; // Verify we break edges at a good point // A simple alg would make 3 breaks, below only requires b->i to break @@ -101,7 +103,7 @@ public: new V3GraphEdge(gp, g3, q, 2, true); gp->stronglyConnected(&V3GraphEdge::followAlwaysTrue); - dump(); + dumpSelf(); UASSERT(i->color() != a->color() && a->color() != g2->color() && g2->color() != q->color(), "SelfTest: Separate colors not assigned"); @@ -114,8 +116,8 @@ public: class V3GraphTestAcyc final : public V3GraphTest { public: - virtual string name() override { return "acyc"; } - virtual void runTest() override { + string name() override { return "acyc"; } + void runTest() override { V3Graph* gp = &m_graph; // Verify we break edges at a good point // A simple alg would make 3 breaks, below only requires b->i to break @@ -136,14 +138,14 @@ public: gp->acyclic(&V3GraphEdge::followAlwaysTrue); gp->order(); - dump(); + dumpSelf(); } }; class V3GraphTestVars final : public V3GraphTest { public: - virtual string name() override { return "vars"; } - virtual void runTest() override { + string name() override { return "vars"; } + void runTest() override { V3Graph* gp = &m_graph; V3GraphTestVertex* clk = new V3GraphTestVarVertex(gp, "$clk"); @@ -253,7 +255,7 @@ public: gp->acyclic(&V3GraphEdge::followAlwaysTrue); gp->order(); - dump(); + dumpSelf(); } }; @@ -268,15 +270,15 @@ class V3GraphTestImport final : public V3GraphTest { #endif public: - virtual string name() override { return "import"; } - virtual void runTest() override { + string name() override { return "import"; } + void runTest() override { V3Graph* const gp = &m_graph; dotImport(); - dump(); + dumpSelf(); gp->acyclic(&V3GraphEdge::followAlwaysTrue); - dump(); + dumpSelf(); gp->rank(&V3GraphEdge::followAlwaysTrue); - dump(); + dumpSelf(); } }; diff --git a/src/V3Hash.h b/src/V3Hash.h index 13f86dd6d..c5dd1b631 100644 --- a/src/V3Hash.h +++ b/src/V3Hash.h @@ -26,7 +26,7 @@ class V3Hash final { uint32_t m_value; // The 32-bit hash value. - inline static uint32_t combine(uint32_t a, uint32_t b) { + static uint32_t combine(uint32_t a, uint32_t b) { return a ^ (b + 0x9e3779b9 + (a << 6) + (a >> 2)); } diff --git a/src/V3Hasher.cpp b/src/V3Hasher.cpp index 53a276c89..97fef5716 100644 --- a/src/V3Hasher.cpp +++ b/src/V3Hasher.cpp @@ -21,6 +21,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Visitor that computes node hashes @@ -35,7 +37,6 @@ private: const bool m_cacheInUser4; // Use user4 to cache each V3Hash? // METHODS - VL_DEBUG_FUNC; // Declare debug() V3Hash hashNodeAndIterate(AstNode* nodep, bool hashDType, bool hashChildren, std::function&& f) { @@ -80,7 +81,7 @@ private: //------------------------------------------------------------ // AstNode - Warns to help find missing cases - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { #if VL_DEBUG UINFO(0, "%Warning: Hashing node as AstNode: " << nodep << endl); #endif @@ -89,93 +90,93 @@ private: //------------------------------------------------------------ // AstNodeDType - virtual void visit(AstNodeArrayDType* nodep) override { + void visit(AstNodeArrayDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { iterateNull(nodep->virtRefDTypep()); m_hash += nodep->left(); m_hash += nodep->right(); }); } - virtual void visit(AstNodeUOrStructDType* nodep) override { + void visit(AstNodeUOrStructDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, false, [=]() { // m_hash += nodep->uniqueNum(); }); } - virtual void visit(AstParamTypeDType* nodep) override { + void visit(AstParamTypeDType* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { m_hash += nodep->name(); m_hash += nodep->varType(); }); } - virtual void visit(AstMemberDType* nodep) override { + void visit(AstMemberDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // m_hash += nodep->name(); }); } - virtual void visit(AstDefImplicitDType* nodep) override { + void visit(AstDefImplicitDType* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // m_hash += nodep->uniqueNum(); }); } - virtual void visit(AstAssocArrayDType* nodep) override { + void visit(AstAssocArrayDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { iterateNull(nodep->virtRefDTypep()); iterateNull(nodep->virtRefDType2p()); }); } - virtual void visit(AstDynArrayDType* nodep) override { + void visit(AstDynArrayDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // iterateNull(nodep->virtRefDTypep()); }); } - virtual void visit(AstUnsizedArrayDType* nodep) override { + void visit(AstUnsizedArrayDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // iterateNull(nodep->virtRefDTypep()); }); } - virtual void visit(AstWildcardArrayDType* nodep) override { + void visit(AstWildcardArrayDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // iterateNull(nodep->virtRefDTypep()); }); } - virtual void visit(AstBasicDType* nodep) override { + void visit(AstBasicDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { m_hash += nodep->keyword(); m_hash += nodep->nrange().left(); m_hash += nodep->nrange().right(); }); } - virtual void visit(AstConstDType* nodep) override { + void visit(AstConstDType* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // iterateNull(nodep->virtRefDTypep()); }); } - virtual void visit(AstClassRefDType* nodep) override { + void visit(AstClassRefDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // iterateNull(nodep->classp()); }); } - virtual void visit(AstIfaceRefDType* nodep) override { + void visit(AstIfaceRefDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // iterateNull(nodep->cellp()); }); } - virtual void visit(AstQueueDType* nodep) override { + void visit(AstQueueDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // iterateNull(nodep->virtRefDTypep()); }); } - virtual void visit(AstRefDType* nodep) override { + void visit(AstRefDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { m_hash += nodep->name(); iterateNull(nodep->typedefp()); iterateNull(nodep->refDTypep()); }); } - virtual void visit(AstVoidDType* nodep) override { + void visit(AstVoidDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {}); } - virtual void visit(AstEnumDType* nodep) override { + void visit(AstEnumDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, false, [=]() { // m_hash += nodep->uniqueNum(); }); @@ -183,23 +184,23 @@ private: //------------------------------------------------------------ // AstNodeMath - virtual void visit(AstNodeMath* nodep) override { + void visit(AstNodeMath* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); } - virtual void visit(AstConst* nodep) override { + void visit(AstConst* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // m_hash += nodep->num().toHash(); }); } - virtual void visit(AstNullCheck* nodep) override { + void visit(AstNullCheck* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); } - virtual void visit(AstCCast* nodep) override { + void visit(AstCCast* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // m_hash += nodep->size(); }); } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { if (nodep->varScopep()) { iterateNull(nodep->varScopep()); @@ -209,28 +210,28 @@ private: } }); } - virtual void visit(AstVarXRef* nodep) override { + void visit(AstVarXRef* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { iterateNull(nodep->varp()); m_hash += nodep->dotted(); }); } - virtual void visit(AstMemberSel* nodep) override { + void visit(AstMemberSel* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // m_hash += nodep->name(); }); } - virtual void visit(AstFScanF* nodep) override { + void visit(AstFScanF* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // m_hash += nodep->text(); }); } - virtual void visit(AstSScanF* nodep) override { + void visit(AstSScanF* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // m_hash += nodep->text(); }); } - virtual void visit(AstAddrOfCFunc* nodep) override { + void visit(AstAddrOfCFunc* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // iterateNull(nodep->funcp()); }); @@ -238,56 +239,56 @@ private: //------------------------------------------------------------ // AstNodeStmt - virtual void visit(AstNodeStmt* nodep) override { + void visit(AstNodeStmt* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {}); } - virtual void visit(AstNodeText* nodep) override { + void visit(AstNodeText* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // m_hash += nodep->text(); }); } - virtual void visit(AstNodeCCall* nodep) override { + void visit(AstNodeCCall* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // iterateNull(nodep->funcp()); }); } - virtual void visit(AstNodeFTaskRef* nodep) override { + void visit(AstNodeFTaskRef* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { iterateNull(nodep->taskp()); iterateNull(nodep->classOrPackagep()); }); } - virtual void visit(AstCMethodHard* nodep) override { + void visit(AstCMethodHard* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // m_hash += nodep->name(); }); } - virtual void visit(AstCoverInc* nodep) override { + void visit(AstCoverInc* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // iterateNull(nodep->declp()); }); } - virtual void visit(AstDisplay* nodep) override { + void visit(AstDisplay* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // m_hash += nodep->displayType(); }); } - virtual void visit(AstMonitorOff* nodep) override { + void visit(AstMonitorOff* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // m_hash += nodep->off(); }); } - virtual void visit(AstJumpGo* nodep) override { + void visit(AstJumpGo* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // iterateNull(nodep->labelp()); }); } - virtual void visit(AstTraceInc* nodep) override { + void visit(AstTraceInc* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // iterateNull(nodep->declp()); }); } - virtual void visit(AstNodeCoverOrAssert* nodep) override { + void visit(AstNodeCoverOrAssert* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // m_hash += nodep->name(); }); @@ -295,62 +296,62 @@ private: //------------------------------------------------------------ // AstNode direct descendents - virtual void visit(AstNodeRange* nodep) override { + void visit(AstNodeRange* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, false, [=]() { // m_hash += nodep->origName(); }); } - virtual void visit(AstNodePreSel* nodep) override { + void visit(AstNodePreSel* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); } - virtual void visit(AstClassExtends* nodep) override { + void visit(AstClassExtends* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); } - virtual void visit(AstSelLoopVars* nodep) override { + void visit(AstSelLoopVars* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); } - virtual void visit(AstDefParam* nodep) override { + void visit(AstDefParam* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); } - virtual void visit(AstArg* nodep) override { + void visit(AstArg* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); } - virtual void visit(AstParseRef* nodep) override { + void visit(AstParseRef* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { m_hash += nodep->expect(); m_hash += nodep->name(); }); } - virtual void visit(AstClassOrPackageRef* nodep) override { + void visit(AstClassOrPackageRef* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // iterateNull(nodep->classOrPackageNodep()); }); } - virtual void visit(AstSenItem* nodep) override { + void visit(AstSenItem* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // m_hash += nodep->edgeType(); }); } - virtual void visit(AstSenTree* nodep) override { + void visit(AstSenTree* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); } - virtual void visit(AstSFormatF* nodep) override { + void visit(AstSFormatF* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // m_hash += nodep->text(); }); } - virtual void visit(AstElabDisplay* nodep) override { + void visit(AstElabDisplay* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // m_hash += nodep->displayType(); }); } - virtual void visit(AstInitItem* nodep) override { + void visit(AstInitItem* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); } - virtual void visit(AstInitArray* nodep) override { + void visit(AstInitArray* nodep) override { if (const AstAssocArrayDType* const dtypep = VN_CAST(nodep->dtypep(), AssocArrayDType)) { if (nodep->defaultp()) { m_hash @@ -376,22 +377,22 @@ private: }); } } - virtual void visit(AstPragma* nodep) override { + void visit(AstPragma* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // m_hash += nodep->pragType(); }); } - virtual void visit(AstAttrOf* nodep) override { + void visit(AstAttrOf* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // m_hash += nodep->attrType(); }); } - virtual void visit(AstNodeFile* nodep) override { + void visit(AstNodeFile* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // m_hash += nodep->name(); }); } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // // We might be in a recursive function, if so on *second* call // here we need to break what would be an infinite loop. @@ -402,90 +403,90 @@ private: m_hash += nodep->isLoose(); }); } - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { m_hash += nodep->name(); m_hash += nodep->varType(); }); } - virtual void visit(AstScope* nodep) override { + void visit(AstScope* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, false, [=]() { m_hash += nodep->name(); iterateNull(nodep->aboveScopep()); }); } - virtual void visit(AstVarScope* nodep) override { + void visit(AstVarScope* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { iterateNull(nodep->varp()); iterateNull(nodep->scopep()); }); } - virtual void visit(AstEnumItem* nodep) override { + void visit(AstEnumItem* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // m_hash += nodep->name(); }); } - virtual void visit(AstTypedef* nodep) override { + void visit(AstTypedef* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // m_hash += nodep->name(); }); } - virtual void visit(AstTypedefFwd* nodep) override { + void visit(AstTypedefFwd* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // m_hash += nodep->name(); }); } - virtual void visit(AstActive* nodep) override { + void visit(AstActive* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // iterateNull(nodep->sensesp()); }); } - virtual void visit(AstCell* nodep) override { + void visit(AstCell* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { m_hash += nodep->name(); iterateNull(nodep->modp()); }); } - virtual void visit(AstCellInline* nodep) override { + void visit(AstCellInline* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { m_hash += nodep->name(); iterateNull(nodep->scopep()); }); } - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstNodeFTask* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // m_hash += nodep->name(); }); } - virtual void visit(AstModport* nodep) override { + void visit(AstModport* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // m_hash += nodep->name(); }); } - virtual void visit(AstModportVarRef* nodep) override { + void visit(AstModportVarRef* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { m_hash += nodep->name(); iterateNull(nodep->varp()); }); } - virtual void visit(AstModportFTaskRef* nodep) override { + void visit(AstModportFTaskRef* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { m_hash += nodep->name(); iterateNull(nodep->ftaskp()); }); } - virtual void visit(AstMTaskBody* nodep) override { + void visit(AstMTaskBody* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); } - virtual void visit(AstNodeProcedure* nodep) override { + void visit(AstNodeProcedure* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); } - virtual void visit(AstNodeBlock* nodep) override { + void visit(AstNodeBlock* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // m_hash += nodep->name(); }); } - virtual void visit(AstPin* nodep) override { + void visit(AstPin* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { m_hash += nodep->name(); m_hash += nodep->pinNum(); @@ -504,7 +505,7 @@ public: iterate(const_cast(nodep)); } V3Hash finalHash() const { return m_hash; } - virtual ~HasherVisitor() override = default; + ~HasherVisitor() override = default; }; //###################################################################### diff --git a/src/V3Hasher.h b/src/V3Hasher.h index 9944f84b1..823a1a074 100644 --- a/src/V3Hasher.h +++ b/src/V3Hasher.h @@ -40,7 +40,6 @@ public: ~V3Hasher() = default; // METHODS - VL_DEBUG_FUNC; // Declare debug() // Compute hash of node. This method caches the hash in the node's user4(). V3Hash operator()(AstNode* nodep) const; diff --git a/src/V3HierBlock.cpp b/src/V3HierBlock.cpp index e7ac8dd9b..a5f2fa38a 100644 --- a/src/V3HierBlock.cpp +++ b/src/V3HierBlock.cpp @@ -86,6 +86,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + static string V3HierCommandArgsFileName(const string& prefix, bool forCMake) { return v3Global.opt.makeDir() + "/" + prefix + (forCMake ? "_hierCMakeArgs.f" : "_hierMkArgs.f"); @@ -250,7 +252,7 @@ class HierBlockUsageCollectVisitor final : public VNVisitor { ModuleSet m_referred; // Modules that have hier_block pragma V3HierBlock::GParams m_gparams; // list of variables that is VVarType::GPARAM - virtual void visit(AstModule* nodep) override { + void visit(AstModule* nodep) override { // Don't visit twice if (nodep->user1SetOnce()) return; UINFO(5, "Checking " << nodep->prettyNameQ() << " from " @@ -277,7 +279,7 @@ class HierBlockUsageCollectVisitor final : public VNVisitor { } m_gparams = prevGParams; } - virtual void visit(AstCell* nodep) override { + void visit(AstCell* nodep) override { // Visit used module here to know that the module is hier_block or not. // This visitor behaves almost depth first search if (AstModule* const modp = VN_CAST(nodep->modp(), Module)) { @@ -287,22 +289,21 @@ class HierBlockUsageCollectVisitor final : public VNVisitor { // Nothing to do for interface because hierarchical block does not exist // beyond interface. } - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { if (m_modp && m_modp->hierBlock() && nodep->isIfaceRef() && !nodep->isIfaceParent()) { nodep->v3error("Modport cannot be used at the hierarchical block boundary"); } if (nodep->isGParam() && nodep->overriddenParam()) m_gparams.push_back(nodep); } - virtual void visit(AstNodeMath*) override {} // Accelerate - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: HierBlockUsageCollectVisitor(V3HierBlockPlan* planp, AstNetlist* netlist) : m_planp{planp} { iterateChildren(netlist); } - VL_DEBUG_FUNC; // Declare debug() }; //###################################################################### diff --git a/src/V3HierBlock.h b/src/V3HierBlock.h index b4fe14374..7526423d5 100644 --- a/src/V3HierBlock.h +++ b/src/V3HierBlock.h @@ -67,7 +67,6 @@ public: : m_modp{modp} , m_gparams{gparams} {} ~V3HierBlock(); - VL_DEBUG_FUNC; // Declare debug() void addParent(V3HierBlock* parentp) { m_parents.insert(parentp); } void addChild(V3HierBlock* childp) { m_children.insert(childp); } @@ -107,7 +106,6 @@ public: using iterator = HierMap::iterator; using const_iterator = HierMap::const_iterator; using HierVector = std::vector; - VL_DEBUG_FUNC; // Declare debug() void add(const AstNodeModule* modp, const std::vector& gparams); void registerUsage(const AstNodeModule* parentp, const AstNodeModule* childp); diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index 40f54dcce..cad404fbc 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -40,6 +40,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + // CONFIG static const int INLINE_MODS_SMALLER = 100; // If a mod is < this # nodes, can always inline it @@ -95,7 +97,6 @@ private: std::unordered_map m_instances; // METHODS - VL_DEBUG_FUNC; // Declare debug() void cantInline(const char* reason, bool hard) { if (hard) { if (m_modp->user2() != CIL_NOTHARD) { @@ -112,7 +113,7 @@ private: } // VISITORS - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { UASSERT_OBJ(!m_modp, nodep, "Unsupported: Nested modules"); m_modp = nodep; m_allMods.push_back(nodep); @@ -130,19 +131,19 @@ private: iterateChildren(nodep); m_modp = nullptr; } - virtual void visit(AstClass* nodep) override { + void visit(AstClass* nodep) override { // TODO allow inlining of modules that have classes // (Probably wait for new inliner scheme) cantInline("class", true); iterateChildren(nodep); } - virtual void visit(AstCell* nodep) override { + void visit(AstCell* nodep) override { m_moduleState(nodep->modp()).m_cellRefs++; m_moduleState(m_modp).m_childCells.push_back(nodep); m_instances[m_modp][nodep->modp()]++; iterateChildren(nodep); } - virtual void visit(AstPragma* nodep) override { + void visit(AstPragma* nodep) override { if (nodep->pragType() == VPragmaType::INLINE_MODULE) { if (!m_modp) { nodep->v3error("Inline pragma not under a module"); // LCOV_EXCL_LINE @@ -162,28 +163,28 @@ private: VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } } - virtual void visit(AstVarXRef* nodep) override { + void visit(AstVarXRef* nodep) override { // Remove link. V3LinkDot will reestablish it after inlining. nodep->varp(nullptr); } - virtual void visit(AstNodeFTaskRef* nodep) override { + void visit(AstNodeFTaskRef* nodep) override { // Remove link. V3LinkDot will reestablish it after inlining. // MethodCalls not currently supported by inliner, so keep linked if (!nodep->classOrPackagep() && !VN_IS(nodep, MethodCall)) nodep->taskp(nullptr); iterateChildren(nodep); } - virtual void visit(AstAlways* nodep) override { + void visit(AstAlways* nodep) override { m_modp->user4Inc(); // statement count iterateChildren(nodep); } - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { // Don't count assignments, as they'll likely flatten out // Still need to iterate though to nullify VarXRefs const int oldcnt = m_modp->user4(); iterateChildren(nodep); m_modp->user4(oldcnt); } - virtual void visit(AstNetlist* nodep) override { + void visit(AstNetlist* nodep) override { // Build ModuleState, user2, and user4 for all modules. // Also build m_allMods and m_instances. iterateChildren(nodep); @@ -226,7 +227,7 @@ private: } } //-------------------- - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { if (m_modp) m_modp->user4Inc(); // Inc statement count iterateChildren(nodep); } @@ -237,7 +238,7 @@ public: : m_moduleState{moduleState} { iterate(nodep); } - virtual ~InlineMarkVisitor() override { + ~InlineMarkVisitor() override { V3Stats::addStat("Optimizations, Inline unsupported", m_statUnsup); } }; @@ -256,11 +257,8 @@ private: AstNodeModule* const m_modp; // Current module const AstCell* const m_cellp; // Cell being cloned - // METHODS - VL_DEBUG_FUNC; // Declare debug() - // VISITORS - virtual void visit(AstCellInline* nodep) override { + void visit(AstCellInline* nodep) override { // Inlined cell under the inline cell, need to move to avoid conflicts nodep->unlinkFrBack(); m_modp->addInlinesp(nodep); @@ -270,20 +268,20 @@ private: // Do CellInlines under this, but don't move them iterateChildren(nodep); } - virtual void visit(AstCell* nodep) override { + void visit(AstCell* nodep) override { // Cell under the inline cell, need to rename to avoid conflicts nodep->name(m_cellp->name() + "__DOT__" + nodep->name()); iterateChildren(nodep); } - virtual void visit(AstClass* nodep) override { + void visit(AstClass* nodep) override { nodep->name(m_cellp->name() + "__DOT__" + nodep->name()); iterateChildren(nodep); } - virtual void visit(AstModule* nodep) override { + void visit(AstModule* nodep) override { m_renamedInterfaces.clear(); iterateChildren(nodep); } - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { if (nodep->user2p()) { // Make an assignment, so we'll trace it properly // user2p is either a const or a var. @@ -294,15 +292,15 @@ private: UASSERT_OBJ(exprconstp || exprvarrefp, nodep, "Unknown interconnect type; pinReconnectSimple should have cleared up"); if (exprconstp) { - m_modp->addStmtp(new AstAssignW(flp, new AstVarRef(flp, nodep, VAccess::WRITE), - exprconstp->cloneTree(false))); + m_modp->addStmtsp(new AstAssignW(flp, new AstVarRef(flp, nodep, VAccess::WRITE), + exprconstp->cloneTree(false))); } else if (nodep->user3()) { // Public variable at the lower module end - we need to make sure we propagate // the logic changes up and down; if we aliased, we might // remove the change detection on the output variable. UINFO(9, "public pin assign: " << exprvarrefp << endl); UASSERT_OBJ(!nodep->isNonOutput(), nodep, "Outputs only - inputs use AssignAlias"); - m_modp->addStmtp( + m_modp->addStmtsp( new AstAssignW(flp, new AstVarRef(flp, exprvarrefp->varp(), VAccess::WRITE), new AstVarRef(flp, nodep, VAccess::READ))); } else if (nodep->isSigPublic() && VN_IS(nodep->dtypep(), UnpackArrayDType)) { @@ -310,11 +308,11 @@ private: // instead of aliased, because otherwise it will pass V3Slice and invalid // code will be emitted. UINFO(9, "assign to public and unpacked: " << nodep << endl); - m_modp->addStmtp( + m_modp->addStmtsp( new AstAssignW{flp, new AstVarRef{flp, nodep, VAccess::WRITE}, new AstVarRef{flp, exprvarrefp->varp(), VAccess::READ}}); } else if (nodep->isIfaceRef()) { - m_modp->addStmtp( + m_modp->addStmtsp( new AstAssignVarScope(flp, new AstVarRef(flp, nodep, VAccess::WRITE), new AstVarRef(flp, exprvarrefp->varp(), VAccess::READ))); FileLine* const flbp = exprvarrefp->varp()->fileline(); @@ -323,7 +321,7 @@ private: } else { // Do to inlining child's variable now within the same // module, so a AstVarRef not AstVarXRef below - m_modp->addStmtp( + m_modp->addStmtsp( new AstAssignAlias(flp, new AstVarRef(flp, nodep, VAccess::WRITE), new AstVarRef(flp, exprvarrefp->varp(), VAccess::READ))); FileLine* const flbp = exprvarrefp->varp()->fileline(); @@ -360,17 +358,17 @@ private: if (debug() >= 9) nodep->dumpTree(cout, "varchanged:"); if (debug() >= 9 && nodep->valuep()) nodep->valuep()->dumpTree(cout, "varchangei:"); } - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstNodeFTask* nodep) override { // Function under the inline cell, need to rename to avoid conflicts nodep->name(m_cellp->name() + "__DOT__" + nodep->name()); iterateChildren(nodep); } - virtual void visit(AstTypedef* nodep) override { + void visit(AstTypedef* nodep) override { // Typedef under the inline cell, need to rename to avoid conflicts nodep->name(m_cellp->name() + "__DOT__" + nodep->name()); iterateChildren(nodep); } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { if (nodep->varp()->user2p() // It's being converted to an alias. && !nodep->varp()->user3() // Don't constant propagate aliases (we just made) @@ -388,7 +386,7 @@ private: } nodep->name(nodep->varp()->name()); } - virtual void visit(AstVarXRef* nodep) override { + void visit(AstVarXRef* nodep) override { // Track what scope it was originally under so V3LinkDot can resolve it nodep->inlinedDots(VString::dot(m_cellp->name(), ".", nodep->inlinedDots())); for (string tryname = nodep->dotted(); true;) { @@ -406,7 +404,7 @@ private: } iterateChildren(nodep); } - virtual void visit(AstNodeFTaskRef* nodep) override { + void visit(AstNodeFTaskRef* nodep) override { // Track what scope it was originally under so V3LinkDot can resolve it nodep->inlinedDots(VString::dot(m_cellp->name(), ".", nodep->inlinedDots())); if (m_renamedInterfaces.count(nodep->dotted())) { @@ -417,30 +415,30 @@ private: } // Not needed, as V3LinkDot doesn't care about typedefs - // virtual void visit(AstRefDType* nodep) override {} + // void visit(AstRefDType* nodep) override {} - virtual void visit(AstScopeName* nodep) override { + void visit(AstScopeName* nodep) override { // If there's a %m in the display text, we add a special node that will contain the name() // Similar code in V3Begin // To keep correct visual order, must add before other Text's - AstNode* afterp = nodep->scopeAttrp(); + AstText* afterp = nodep->scopeAttrp(); if (afterp) afterp->unlinkFrBackWithNext(); - nodep->scopeAttrp( + nodep->addScopeAttrp( new AstText{nodep->fileline(), std::string{"__DOT__"} + m_cellp->name()}); - if (afterp) nodep->scopeAttrp(afterp); + if (afterp) nodep->addScopeAttrp(afterp); afterp = nodep->scopeEntrp(); if (afterp) afterp->unlinkFrBackWithNext(); - nodep->scopeEntrp( + nodep->addScopeEntrp( new AstText{nodep->fileline(), std::string{"__DOT__"} + m_cellp->name()}); - if (afterp) nodep->scopeEntrp(afterp); + if (afterp) nodep->addScopeEntrp(afterp); iterateChildren(nodep); } - virtual void visit(AstCoverDecl* nodep) override { + void visit(AstCoverDecl* nodep) override { // Fix path in coverage statements nodep->hier(VString::dot(m_cellp->prettyName(), ".", nodep->hier())); iterateChildren(nodep); } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -449,7 +447,7 @@ public: , m_cellp{cellp} { iterate(cloneModp); } - virtual ~InlineRelinkVisitor() override = default; + ~InlineRelinkVisitor() override = default; }; //###################################################################### @@ -478,8 +476,6 @@ private: VDouble0 m_statCells; // Statistic tracking // METHODS - VL_DEBUG_FUNC; // Declare debug() - void inlineCell(AstCell* nodep) { UINFO(5, " Inline CELL " << nodep << endl); @@ -566,7 +562,7 @@ private: // Move statements under the module we are inlining into if (AstNode* const stmtsp = newmodp->stmtsp()) { stmtsp->unlinkFrBackWithNext(); - m_modp->addStmtp(stmtsp); + m_modp->addStmtsp(stmtsp); } // Clear any leftover ports, etc VL_DO_DANGLING(newmodp->deleteTree(), newmodp); @@ -576,13 +572,13 @@ private: } // VISITORS - virtual void visit(AstNetlist* nodep) override { + void visit(AstNetlist* nodep) override { // Iterate modules backwards, in bottom-up order. Required! iterateAndNextConstNullBackwards(nodep->modulesp()); // Clean up AstIfaceRefDType references iterateChildren(nodep->typeTablep()); } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { UASSERT_OBJ(!m_modp, nodep, "Unsupported: Nested modules"); m_modp = nodep; // Iterate the stored cells directly to reduce traversal @@ -592,7 +588,7 @@ private: m_moduleState(nodep).m_childCells.clear(); m_modp = nullptr; } - virtual void visit(AstIfaceRefDType* nodep) override { + void visit(AstIfaceRefDType* nodep) override { if (nodep->user5()) { // The cell has been removed so let's make sure we don't leave a reference to it // This dtype may still be in use by the AstAssignVarScope created earlier @@ -602,15 +598,15 @@ private: } //-------------------- - virtual void visit(AstCell* nodep) override { // LCOV_EXCL_START + void visit(AstCell* nodep) override { // LCOV_EXCL_START nodep->v3fatal("Traversal should have been short circuited"); } - virtual void visit(AstNodeStmt* nodep) override { + void visit(AstNodeStmt* nodep) override { nodep->v3fatal("Traversal should have been short circuited"); } // LCOV_EXCL_STOP - virtual void visit(AstNodeFile*) override {} // Accelerate - virtual void visit(AstNodeDType*) override {} // Accelerate - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNodeFile*) override {} // Accelerate + void visit(AstNodeDType*) override {} // Accelerate + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -618,7 +614,7 @@ public: : m_moduleState{moduleState} { iterate(nodep); } - virtual ~InlineVisitor() override { + ~InlineVisitor() override { V3Stats::addStat("Optimizations, Inlined instances", m_statCells); } }; @@ -635,12 +631,9 @@ private: string m_scope; // Scope name - // METHODS - VL_DEBUG_FUNC; // Declare debug() - // VISITORS - virtual void visit(AstNetlist* nodep) override { iterateChildren(nodep->topModulep()); } - virtual void visit(AstCell* nodep) override { + void visit(AstNetlist* nodep) override { iterateChildren(nodep->topModulep()); } + void visit(AstCell* nodep) override { VL_RESTORER(m_scope); if (m_scope.empty()) { m_scope = nodep->name(); @@ -649,7 +642,7 @@ private: } if (VN_IS(nodep->modp(), Iface)) { - nodep->addIntfRefp(new AstIntfRef{nodep->fileline(), m_scope}); + nodep->addIntfRefsp(new AstIntfRef{nodep->fileline(), m_scope}); } { AstNodeModule* const modp = nodep->modp(); @@ -666,14 +659,14 @@ private: if ((cellp = VN_CAST(fromVarp->user1p(), Cell)) || (cellp = irdtp->cellp())) { varp->user1p(cellp); const string alias = m_scope + "__DOT__" + pinp->name(); - cellp->addIntfRefp(new AstIntfRef(pinp->fileline(), alias)); + cellp->addIntfRefsp(new AstIntfRef(pinp->fileline(), alias)); } } iterateChildren(modp); } } - virtual void visit(AstAssignVarScope* nodep) override { + void visit(AstAssignVarScope* nodep) override { // Reference const AstVarRef* const reflp = VN_CAST(nodep->lhsp(), VarRef); // What the reference refers to @@ -695,17 +688,17 @@ private: string alias; if (!m_scope.empty()) alias = m_scope + "__DOT__"; alias += varlp->name(); - cellp->addIntfRefp(new AstIntfRef(varlp->fileline(), alias)); + cellp->addIntfRefsp(new AstIntfRef(varlp->fileline(), alias)); } //-------------------- - virtual void visit(AstNodeMath*) override {} // Accelerate - virtual void visit(AstNodeStmt*) override {} // Accelerate - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNodeStmt*) override {} // Accelerate + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit InlineIntfRefVisitor(AstNode* nodep) { iterate(nodep); } - virtual ~InlineIntfRefVisitor() override = default; + ~InlineIntfRefVisitor() override = default; }; //###################################################################### @@ -734,5 +727,5 @@ void V3Inline::inlineAll(AstNetlist* nodep) { } { InlineIntfRefVisitor{nodep}; } - V3Global::dumpCheckGlobalTree("inline", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("inline", 0, dumpTree() >= 3); } diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index e66936eec..328318dc5 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -32,6 +32,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Inst state, as a visitor of each AstNode @@ -45,11 +47,8 @@ private: // STATE AstCell* m_cellp = nullptr; // Current cell - // METHODS - VL_DEBUG_FUNC; // Declare debug() - // VISITORS - virtual void visit(AstCell* nodep) override { + void visit(AstCell* nodep) override { UINFO(4, " CELL " << nodep << endl); m_cellp = nodep; // VV***** We reset user1p() on each cell!!! @@ -57,7 +56,7 @@ private: iterateChildren(nodep); m_cellp = nullptr; } - virtual void visit(AstPin* nodep) override { + void visit(AstPin* nodep) override { // PIN(p,expr) -> ASSIGNW(VARXREF(p),expr) (if sub's input) // or ASSIGNW(expr,VARXREF(p)) (if sub's output) UINFO(4, " PIN " << nodep << endl); @@ -116,7 +115,7 @@ private: VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } - virtual void visit(AstUdpTable* nodep) override { + void visit(AstUdpTable* nodep) override { if (!v3Global.opt.bboxUnsup()) { // If we support primitives, update V3Undriven to remove special case nodep->v3warn(E_UNSUPPORTED, "Unsupported: Verilog 1995 UDP Tables. " @@ -125,17 +124,17 @@ private: } // Save some time - virtual void visit(AstNodeMath*) override {} - virtual void visit(AstNodeAssign*) override {} - virtual void visit(AstAlways*) override {} + void visit(AstNodeMath*) override {} + void visit(AstNodeAssign*) override {} + void visit(AstAlways*) override {} //-------------------- - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit InstVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~InstVisitor() override = default; + ~InstVisitor() override = default; }; //###################################################################### @@ -146,18 +145,16 @@ private: // STATE std::map m_modVarNameMap; // Per module, name of cloned variables - VL_DEBUG_FUNC; // Declare debug() - // VISITORS - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { if (VN_IS(nodep->dtypep(), IfaceRefDType)) { UINFO(8, " dm-1-VAR " << nodep << endl); insert(nodep); } iterateChildren(nodep); } - virtual void visit(AstNodeMath*) override {} // Accelerate - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // METHODS @@ -181,7 +178,7 @@ public: // CONSTRUCTORS InstDeModVarVisitor() = default; - virtual ~InstDeModVarVisitor() override = default; + ~InstDeModVarVisitor() override = default; void main(AstNodeModule* nodep) { UINFO(8, " dmMODULE " << nodep << endl); m_modVarNameMap.clear(); @@ -200,10 +197,8 @@ private: int m_instSelNum = 0; // Current instantiation count 0..N-1 InstDeModVarVisitor m_deModVars; // State of variables for current cell module - VL_DEBUG_FUNC; // Declare debug() - // VISITORS - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { if (VN_IS(nodep->dtypep(), UnpackArrayDType) && VN_IS(VN_AS(nodep->dtypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType)) { UINFO(8, " dv-vec-VAR " << nodep << endl); @@ -239,7 +234,7 @@ private: iterateChildren(nodep); } - virtual void visit(AstCell* nodep) override { + void visit(AstCell* nodep) override { UINFO(4, " CELL " << nodep << endl); // Find submodule vars UASSERT_OBJ(nodep->modp(), nodep, "Unlinked"); @@ -316,7 +311,7 @@ private: } } - virtual void visit(AstPin* nodep) override { + void visit(AstPin* nodep) override { // Any non-direct pins need reconnection with a part-select if (!nodep->exprp()) return; // No-connect if (m_cellRangep) { @@ -478,13 +473,13 @@ private: } //-------------------- - virtual void visit(AstNodeMath*) override {} // Accelerate - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit InstDeVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~InstDeVisitor() override = default; + ~InstDeVisitor() override = default; }; //###################################################################### @@ -492,7 +487,6 @@ public: class InstStatic final { private: - VL_DEBUG_FUNC; // Declare debug() InstStatic() = default; // Static class static AstNode* extendOrSel(FileLine* fl, AstNode* rhsp, AstNode* cmpWidthp) { @@ -622,11 +616,11 @@ void V3Inst::checkOutputShort(AstPin* nodep) { void V3Inst::instAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { InstVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("inst", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("inst", 0, dumpTree() >= 3); } void V3Inst::dearrayAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { InstDeVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("dearray", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6); + V3Global::dumpCheckGlobalTree("dearray", 0, dumpTree() >= 6); } diff --git a/src/V3InstrCount.cpp b/src/V3InstrCount.cpp index d0ec37562..1f2cc3a9b 100644 --- a/src/V3InstrCount.cpp +++ b/src/V3InstrCount.cpp @@ -24,6 +24,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + /// Estimate the instruction cost for executing all logic within and below /// a given AST node. Note this estimates the number of instructions we'll /// execute, not the number we'll generate. That is, for conditionals, @@ -75,7 +77,7 @@ public: , m_osp{osp} { if (nodep) iterate(nodep); } - virtual ~InstrCountVisitor() override = default; + ~InstrCountVisitor() override = default; // METHODS uint32_t instrCount() const { return m_instrCount; } @@ -117,7 +119,7 @@ private: } // VISITORS - virtual void visit(AstNodeSel* nodep) override { + void visit(AstNodeSel* nodep) override { // This covers both AstArraySel and AstWordSel // // If some vector is a bazillion dwords long, and we're selecting 1 @@ -128,7 +130,7 @@ private: const VisitBase vb{this, nodep}; iterateAndNextNull(nodep->bitp()); } - virtual void visit(AstSel* nodep) override { + void visit(AstSel* nodep) override { // Similar to AstNodeSel above, a small select into a large vector // is not expensive. Count the cost of the AstSel itself (scales with // its width) and the cost of the lsbp() and widthp() nodes, but not @@ -137,13 +139,13 @@ private: iterateAndNextNull(nodep->lsbp()); iterateAndNextNull(nodep->widthp()); } - virtual void visit(AstSliceSel* nodep) override { // LCOV_EXCL_LINE + void visit(AstSliceSel* nodep) override { // LCOV_EXCL_LINE nodep->v3fatalSrc("AstSliceSel unhandled"); } - virtual void visit(AstMemberSel* nodep) override { // LCOV_EXCL_LINE + void visit(AstMemberSel* nodep) override { // LCOV_EXCL_LINE nodep->v3fatalSrc("AstMemberSel unhandled"); } - virtual void visit(AstConcat* nodep) override { + void visit(AstConcat* nodep) override { // Nop. // // Ignore concat. The problem with counting concat is that when we @@ -163,14 +165,14 @@ private: // the widths of the operands (ignored here). markCost(nodep); } - virtual void visit(AstNodeIf* nodep) override { + void visit(AstNodeIf* nodep) override { const VisitBase vb{this, nodep}; iterateAndNextNull(nodep->condp()); const uint32_t savedCount = m_instrCount; UINFO(8, "ifsp:\n"); m_instrCount = 0; - iterateAndNextNull(nodep->ifsp()); + iterateAndNextNull(nodep->thensp()); uint32_t ifCount = m_instrCount; if (nodep->branchPred().unlikely()) ifCount = 0; @@ -185,10 +187,10 @@ private: if (nodep->elsesp()) nodep->elsesp()->user4(0); // Don't dump it } else { m_instrCount = savedCount + elseCount; - if (nodep->ifsp()) nodep->ifsp()->user4(0); // Don't dump it + if (nodep->thensp()) nodep->thensp()->user4(0); // Don't dump it } } - virtual void visit(AstNodeCond* nodep) override { + void visit(AstNodeCond* nodep) override { // Just like if/else above, the ternary operator only evaluates // one of the two expressions, so only count the max. const VisitBase vb{this, nodep}; @@ -197,23 +199,23 @@ private: UINFO(8, "?\n"); m_instrCount = 0; - iterateAndNextNull(nodep->expr1p()); + iterateAndNextNull(nodep->thenp()); const uint32_t ifCount = m_instrCount; UINFO(8, ":\n"); m_instrCount = 0; - iterateAndNextNull(nodep->expr2p()); + iterateAndNextNull(nodep->elsep()); const uint32_t elseCount = m_instrCount; if (ifCount < elseCount) { m_instrCount = savedCount + elseCount; - if (nodep->expr1p()) nodep->expr1p()->user4(0); // Don't dump it + if (nodep->thenp()) nodep->thenp()->user4(0); // Don't dump it } else { m_instrCount = savedCount + ifCount; - if (nodep->expr2p()) nodep->expr2p()->user4(0); // Don't dump it + if (nodep->elsep()) nodep->elsep()->user4(0); // Don't dump it } } - virtual void visit(AstActive* nodep) override { + void visit(AstActive* nodep) override { // You'd think that the OrderLogicVertex's would be disjoint trees // of stuff in the AST, but it isn't so: V3Order makes an // OrderLogicVertex for each ACTIVE, and then also makes an @@ -229,14 +231,14 @@ private: markCost(nodep); UASSERT_OBJ(nodep == m_startNodep, nodep, "Multiple actives, or not start node"); } - virtual void visit(AstNodeCCall* nodep) override { + void visit(AstNodeCCall* nodep) override { const VisitBase vb{this, nodep}; iterateChildren(nodep); m_tracingCall = true; iterate(nodep->funcp()); UASSERT_OBJ(!m_tracingCall, nodep, "visit(AstCFunc) should have cleared m_tracingCall."); } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { // Don't count a CFunc other than by tracing a call or counting it // from the root UASSERT_OBJ(m_tracingCall || nodep == m_startNodep, nodep, @@ -249,12 +251,11 @@ private: iterateChildren(nodep); } } - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { const VisitBase vb{this, nodep}; iterateChildren(nodep); } - VL_DEBUG_FUNC; // Declare debug() VL_UNCOPYABLE(InstrCountVisitor); }; @@ -276,12 +277,12 @@ public: UASSERT_OBJ(osp, nodep, "Don't call if not dumping"); if (nodep) iterate(nodep); } - virtual ~InstrCountDumpVisitor() override = default; + ~InstrCountDumpVisitor() override = default; private: // METHODS string indent() const { return string(m_depth, ':') + " "; } - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { ++m_depth; if (unsigned costPlus1 = nodep->user4()) { *m_osp << " " << indent() << "cost " << std::setw(6) << std::left << (costPlus1 - 1) @@ -290,7 +291,7 @@ private: } --m_depth; } - VL_DEBUG_FUNC; // Declare debug() + VL_UNCOPYABLE(InstrCountDumpVisitor); }; diff --git a/src/V3LangCode.h b/src/V3LangCode.h index 3877dcf3d..9deef638f 100644 --- a/src/V3LangCode.h +++ b/src/V3LangCode.h @@ -48,22 +48,22 @@ public: "1800-2005", "1800-2009", "1800-2012", "1800-2017"}; return names[m_e]; } - static V3LangCode mostRecent() { return V3LangCode(L1800_2017); } + static V3LangCode mostRecent() { return V3LangCode{L1800_2017}; } bool systemVerilog() const { return m_e == L1800_2005 || m_e == L1800_2009 || m_e == L1800_2012 || m_e == L1800_2017; } bool legal() const { return m_e != L_ERROR; } // enum en m_e; - inline V3LangCode() + V3LangCode() : m_e{L_ERROR} {} // cppcheck-suppress noExplicitConstructor - inline V3LangCode(en _e) + constexpr V3LangCode(en _e) : m_e{_e} {} explicit V3LangCode(const char* textp); - explicit inline V3LangCode(int _e) + explicit V3LangCode(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } }; //###################################################################### diff --git a/src/V3Life.cpp b/src/V3Life.cpp index 112c3920e..4a8067189 100644 --- a/src/V3Life.cpp +++ b/src/V3Life.cpp @@ -36,6 +36,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Structure for global state @@ -94,18 +96,18 @@ public: consumed(); } ~LifeVarEntry() = default; - inline void simpleAssign(AstNodeAssign* assp) { // New simple A=.... assignment + void simpleAssign(AstNodeAssign* assp) { // New simple A=.... assignment m_assignp = assp; m_constp = nullptr; m_everSet = true; if (VN_IS(assp->rhsp(), Const)) m_constp = VN_AS(assp->rhsp(), Const); } - inline void complexAssign() { // A[x]=... or some complicated assignment + void complexAssign() { // A[x]=... or some complicated assignment m_assignp = nullptr; m_constp = nullptr; m_everSet = true; } - inline void consumed() { // Rvalue read of A + void consumed() { // Rvalue read of A m_assignp = nullptr; } AstNodeAssign* assignp() const { return m_assignp; } @@ -128,8 +130,7 @@ class LifeBlock final { LifeMap m_map; // Current active lifetime map for current scope LifeBlock* const m_aboveLifep; // Upper life, or nullptr LifeState* const m_statep; // Current global state - - VL_DEBUG_FUNC; // Declare debug() + bool m_replacedVref = false; // Replaced a variable reference since last clearing public: LifeBlock(LifeBlock* aboveLifep, LifeState* statep) @@ -165,7 +166,7 @@ public: checkRemoveAssign(it); it->second.simpleAssign(assp); } else { - m_map.emplace(nodep, LifeVarEntry(LifeVarEntry::SIMPLEASSIGN(), assp)); + m_map.emplace(nodep, LifeVarEntry{LifeVarEntry::SIMPLEASSIGN{}, assp}); } // lifeDump(); } @@ -175,9 +176,11 @@ public: if (it != m_map.end()) { it->second.complexAssign(); } else { - m_map.emplace(nodep, LifeVarEntry(LifeVarEntry::COMPLEXASSIGN())); + m_map.emplace(nodep, LifeVarEntry{LifeVarEntry::COMPLEXASSIGN{}}); } } + void clearReplaced() { m_replacedVref = false; } + bool replaced() const { return m_replacedVref; } void varUsageReplace(AstVarScope* nodep, AstVarRef* varrefp) { // Variable rvalue. If it references a constant, we can replace it const auto it = m_map.find(nodep); @@ -188,6 +191,7 @@ public: // We'll later constant propagate UINFO(4, " replaceconst: " << varrefp << endl); varrefp->replaceWith(constp->cloneTree(false)); + m_replacedVref = true; VL_DO_DANGLING(varrefp->deleteTree(), varrefp); ++m_statep->m_statAssnCon; return; // **DONE, no longer a var reference** @@ -196,7 +200,7 @@ public: UINFO(4, " usage: " << nodep << endl); it->second.consumed(); } else { - m_map.emplace(nodep, LifeVarEntry(LifeVarEntry::CONSUMED())); + m_map.emplace(nodep, LifeVarEntry{LifeVarEntry::CONSUMED{}}); } } void complexAssignFind(AstVarScope* nodep) { @@ -205,7 +209,7 @@ public: UINFO(4, " casfind: " << it->first << endl); it->second.complexAssign(); } else { - m_map.emplace(nodep, LifeVarEntry(LifeVarEntry::COMPLEXASSIGN())); + m_map.emplace(nodep, LifeVarEntry{LifeVarEntry::COMPLEXASSIGN{}}); } } void consumedFind(AstVarScope* nodep) { @@ -213,7 +217,7 @@ public: if (it != m_map.end()) { it->second.consumed(); } else { - m_map.emplace(nodep, LifeVarEntry(LifeVarEntry::CONSUMED())); + m_map.emplace(nodep, LifeVarEntry{LifeVarEntry::CONSUMED{}}); } } void lifeToAbove() { @@ -284,14 +288,13 @@ private: LifeBlock* m_lifep; // Current active lifetime map for current scope // METHODS - VL_DEBUG_FUNC; // Declare debug() void setNoopt() { m_noopt = true; m_lifep->clear(); } // VISITORS - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { // Consumption/generation of a variable, // it's used so can't elim assignment before this use. UASSERT_OBJ(nodep->varScopep(), nodep, "nullptr"); @@ -305,13 +308,13 @@ private: VL_DO_DANGLING(m_lifep->varUsageReplace(vscp, nodep), nodep); } } - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { // Collect any used variables first, as lhs may also be on rhs // Similar code in V3Dead - const uint64_t lastEdit = AstNode::editCountGbl(); // When it was last edited m_sideEffect = false; + m_lifep->clearReplaced(); iterateAndNextNull(nodep->rhsp()); - if (lastEdit != AstNode::editCountGbl()) { + if (m_lifep->replaced()) { // We changed something, try to constant propagate, but don't delete the // assignment as we still need nodep to remain. V3Const::constifyEdit(nodep->rhsp()); // rhsp may change @@ -325,13 +328,13 @@ private: iterateAndNextNull(nodep->lhsp()); } } - virtual void visit(AstAssignDly* nodep) override { + void visit(AstAssignDly* nodep) override { // Don't treat as normal assign; V3Life doesn't understand time sense iterateChildren(nodep); } //---- Track control flow changes - virtual void visit(AstNodeIf* nodep) override { + void visit(AstNodeIf* nodep) override { UINFO(4, " IF " << nodep << endl); // Condition is part of PREVIOUS block iterateAndNextNull(nodep->condp()); @@ -340,7 +343,7 @@ private: LifeBlock* const elseLifep = new LifeBlock(prevLifep, m_statep); { m_lifep = ifLifep; - iterateAndNextNull(nodep->ifsp()); + iterateAndNextNull(nodep->thensp()); } { m_lifep = elseLifep; @@ -357,7 +360,7 @@ private: VL_DO_DANGLING(delete elseLifep, elseLifep); } - virtual void visit(AstWhile* nodep) override { + void visit(AstWhile* nodep) override { // While's are a problem, as we don't allow loops in the graph. We // may go around the cond/body multiple times. Thus a // lifelication just in the body is ok, but we can't delete an @@ -375,7 +378,7 @@ private: } { m_lifep = bodyLifep; - iterateAndNextNull(nodep->bodysp()); + iterateAndNextNull(nodep->stmtsp()); iterateAndNextNull(nodep->incsp()); } m_lifep = prevLifep; @@ -386,7 +389,7 @@ private: VL_DO_DANGLING(delete condLifep, condLifep); VL_DO_DANGLING(delete bodyLifep, bodyLifep); } - virtual void visit(AstJumpBlock* nodep) override { + void visit(AstJumpBlock* nodep) override { // As with While's we can't predict if a JumpGo will kill us or not // It's worse though as an IF(..., JUMPGO) may change the control flow. // Just don't optimize blocks with labels; they're rare - so far. @@ -404,7 +407,7 @@ private: bodyLifep->lifeToAbove(); VL_DO_DANGLING(delete bodyLifep, bodyLifep); } - virtual void visit(AstNodeCCall* nodep) override { + void visit(AstNodeCCall* nodep) override { // UINFO(4, " CCALL " << nodep << endl); iterateChildren(nodep); // Enter the function and trace it @@ -414,7 +417,7 @@ private: iterate(nodep->funcp()); } } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { // UINFO(4, " CFUNC " << nodep << endl); if (!m_tracingCall && !nodep->entryPoint()) return; m_tracingCall = false; @@ -423,17 +426,17 @@ private: } iterateChildren(nodep); } - virtual void visit(AstUCFunc* nodep) override { + void visit(AstUCFunc* nodep) override { m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment iterateChildren(nodep); } - virtual void visit(AstCMath* nodep) override { + void visit(AstCMath* nodep) override { m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment iterateChildren(nodep); } - virtual void visit(AstVar*) override {} // Don't want varrefs under it - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstVar*) override {} // Don't want varrefs under it + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -446,7 +449,7 @@ public: if (m_lifep) VL_DO_CLEAR(delete m_lifep, m_lifep = nullptr); } } - virtual ~LifeVisitor() override { + ~LifeVisitor() override { if (m_lifep) VL_DO_CLEAR(delete m_lifep, m_lifep = nullptr); } VL_UNCOPYABLE(LifeVisitor); @@ -462,20 +465,20 @@ private: LifeState* const m_statep; // Current state // VISITORS - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { if (nodep->entryPoint()) { // Usage model 1: Simulate all C code, doing lifetime analysis LifeVisitor{nodep, m_statep}; } } - virtual void visit(AstNodeProcedure* nodep) override { + void visit(AstNodeProcedure* nodep) override { // Usage model 2: Cleanup basic blocks LifeVisitor{nodep, m_statep}; } - virtual void visit(AstVar*) override {} // Accelerate - virtual void visit(AstNodeStmt*) override {} // Accelerate - virtual void visit(AstNodeMath*) override {} // Accelerate - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstVar*) override {} // Accelerate + void visit(AstNodeStmt*) override {} // Accelerate + void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -483,7 +486,7 @@ public: : m_statep{statep} { iterate(nodep); } - virtual ~LifeTopVisitor() override = default; + ~LifeTopVisitor() override = default; }; //###################################################################### @@ -495,5 +498,5 @@ void V3Life::lifeAll(AstNetlist* nodep) { LifeState state; LifeTopVisitor{nodep, &state}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("life", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("life", 0, dumpTree() >= 3); } diff --git a/src/V3LifePost.cpp b/src/V3LifePost.cpp index 51b2e0e2c..63758d067 100644 --- a/src/V3LifePost.cpp +++ b/src/V3LifePost.cpp @@ -38,6 +38,8 @@ #include // for std::unique_ptr -> auto_ptr or unique_ptr #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // LifePost class functions @@ -50,25 +52,23 @@ private: // AstVarScope::user4p() -> AstVarScope*, If set, replace this // varscope with specified new one // STATE - // METHODS - VL_DEBUG_FUNC; // Declare debug() // VISITORS - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { const AstVarScope* const vscp = nodep->varScopep(); UASSERT_OBJ(vscp, nodep, "Scope not assigned"); if (AstVarScope* const newvscp = reinterpret_cast(vscp->user4p())) { UINFO(9, " Replace " << nodep << " to " << newvscp << endl); - AstVarRef* const newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->access()); + AstVarRef* const newrefp = new AstVarRef{nodep->fileline(), newvscp, nodep->access()}; nodep->replaceWith(newrefp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { // Only track the top scopes, not lower level functions if (nodep->isTop()) iterateChildren(nodep); } - virtual void visit(AstNodeCCall* nodep) override { + void visit(AstNodeCCall* nodep) override { iterateChildren(nodep); if (!nodep->funcp()->entryPoint()) { // Enter the function and trace it @@ -76,23 +76,23 @@ private: iterate(nodep->funcp()); } } - virtual void visit(AstExecGraph* nodep) override { + void visit(AstExecGraph* nodep) override { // Can just iterate across the MTask bodies in any order. Order // isn't important for LifePostElimVisitor's simple substitution. iterateChildren(nodep); } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { if (!m_tracingCall && !nodep->entryPoint()) return; m_tracingCall = false; iterateChildren(nodep); } - virtual void visit(AstVar*) override {} // Don't want varrefs under it - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstVar*) override {} // Don't want varrefs under it + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit LifePostElimVisitor(AstTopScope* nodep) { iterate(nodep); } - virtual ~LifePostElimVisitor() override = default; + ~LifePostElimVisitor() override = default; }; //###################################################################### @@ -157,8 +157,6 @@ private: std::unique_ptr m_checker; // METHODS - VL_DEBUG_FUNC; // Declare debug() - bool before(const LifeLocation& a, const LifeLocation& b) { if (a.mtaskp == b.mtaskp) return a.sequence < b.sequence; return m_checker->pathExistsFrom(a.mtaskp, b.mtaskp); @@ -250,7 +248,7 @@ private: } // VISITORS - virtual void visit(AstTopScope* nodep) override { + void visit(AstTopScope* nodep) override { AstNode::user4ClearTree(); // user4p() used on entire tree // First, build maps of every location (mtask and sequence @@ -274,7 +272,7 @@ private: // Replace any node4p varscopes with the new scope LifePostElimVisitor{nodep}; } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { // Consumption/generation of a variable, const AstVarScope* const vscp = nodep->varScopep(); UASSERT_OBJ(vscp, nodep, "Scope not assigned"); @@ -283,14 +281,14 @@ private: if (nodep->access().isWriteOrRW()) m_writes[vscp].insert(loc); if (nodep->access().isReadOrRW()) m_reads[vscp].insert(loc); } - virtual void visit(AstAssignPre* nodep) override { + void visit(AstAssignPre* nodep) override { // Do not record varrefs within assign pre. // // The pre-assignment into the dly var should not count as its // first write; we only want to consider reads and writes that // would still happen if the dly var were eliminated. } - virtual void visit(AstAssignPost* nodep) override { + void visit(AstAssignPost* nodep) override { // Don't record ASSIGNPOST in the read/write maps, record them in a // separate map if (const AstVarRef* const rhsp = VN_CAST(nodep->rhsp(), VarRef)) { @@ -302,11 +300,11 @@ private: m_assignposts[dlyVarp] = LifePostLocation(loc, nodep); } } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { // Only track the top scopes, not lower level functions if (nodep->isTop()) iterateChildren(nodep); } - virtual void visit(AstNodeCCall* nodep) override { + void visit(AstNodeCCall* nodep) override { iterateChildren(nodep); if (!nodep->funcp()->entryPoint()) { // Enter the function and trace it @@ -314,7 +312,7 @@ private: iterate(nodep->funcp()); } } - virtual void visit(AstExecGraph* nodep) override { + void visit(AstExecGraph* nodep) override { // Treat the ExecGraph like a call to each mtask body UASSERT_OBJ(!m_mtasksGraphp, nodep, "Cannot handle more than one AstExecGraph"); m_mtasksGraphp = nodep->depGraphp(); @@ -327,19 +325,19 @@ private: } m_execMTaskp = nullptr; } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { if (!m_tracingCall && !nodep->entryPoint()) return; m_tracingCall = false; iterateChildren(nodep); } //----- - virtual void visit(AstVar*) override {} // Don't want varrefs under it - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstVar*) override {} // Don't want varrefs under it + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit LifePostDlyVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~LifePostDlyVisitor() override { + ~LifePostDlyVisitor() override { V3Stats::addStat("Optimizations, Lifetime postassign deletions", m_statAssnDel); } }; @@ -351,5 +349,5 @@ void V3LifePost::lifepostAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); // Mark redundant AssignPost { LifePostDlyVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("life_post", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("life_post", 0, dumpTree() >= 3); } diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp index 03703c2c8..c92a41a10 100644 --- a/src/V3LinkCells.cpp +++ b/src/V3LinkCells.cpp @@ -39,14 +39,16 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Graph subclasses class LinkCellsGraph final : public V3Graph { public: LinkCellsGraph() = default; - virtual ~LinkCellsGraph() override = default; - virtual void loopsMessageCb(V3GraphVertex* vertexp) override; + ~LinkCellsGraph() override = default; + void loopsMessageCb(V3GraphVertex* vertexp) override; }; class LinkCellsVertex final : public V3GraphVertex { @@ -56,12 +58,12 @@ public: LinkCellsVertex(V3Graph* graphp, AstNodeModule* modp) : V3GraphVertex{graphp} , m_modp{modp} {} - virtual ~LinkCellsVertex() override = default; + ~LinkCellsVertex() override = default; AstNodeModule* modp() const { return m_modp; } - virtual string name() const override { return modp()->name(); } - virtual FileLine* fileline() const override { return modp()->fileline(); } + string name() const override { return modp()->name(); } + FileLine* fileline() const override { return modp()->fileline(); } // Recursive modules get space for maximum recursion - virtual uint32_t rankAdder() const override { + uint32_t rankAdder() const override { return m_modp->recursiveClone() ? (1 + v3Global.opt.moduleRecursionDepth()) : 1; } }; @@ -70,8 +72,8 @@ class LibraryVertex final : public V3GraphVertex { public: explicit LibraryVertex(V3Graph* graphp) : V3GraphVertex{graphp} {} - virtual ~LibraryVertex() override = default; - virtual string name() const override { return "*LIBRARY*"; } + ~LibraryVertex() override = default; + string name() const override { return "*LIBRARY*"; } }; void LinkCellsGraph::loopsMessageCb(V3GraphVertex* vertexp) { @@ -118,8 +120,6 @@ private: std::unordered_set m_declfnWarned; // Files we issued DECLFILENAME on string m_origTopModuleName; // original name of the top module - VL_DEBUG_FUNC; // Declare debug() - // METHODS V3GraphVertex* vertex(AstNodeModule* nodep) { // Return corresponding vertex for this module @@ -161,13 +161,13 @@ private: } // VISITs - virtual void visit(AstNetlist* nodep) override { + void visit(AstNetlist* nodep) override { AstNode::user1ClearTree(); readModNames(); iterateChildren(nodep); // Find levels in graph m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue); - m_graph.dumpDotFilePrefixed("linkcells"); + if (dumpGraph()) m_graph.dumpDotFilePrefixed("linkcells"); m_graph.rank(); for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { if (const LinkCellsVertex* const vvertexp = dynamic_cast(itp)) { @@ -181,8 +181,8 @@ private: << "' was not found in design."); } } - virtual void visit(AstConstPool* nodep) override {} - virtual void visit(AstNodeModule* nodep) override { + void visit(AstConstPool* nodep) override {} + void visit(AstNodeModule* nodep) override { // Module: Pick up modnames, so we can resolve cells later VL_RESTORER(m_modp); { @@ -227,7 +227,7 @@ private: } } - virtual void visit(AstIfaceRefDType* nodep) override { + void visit(AstIfaceRefDType* nodep) override { // Cell: Resolve its filename. If necessary, parse it. UINFO(4, "Link IfaceRef: " << nodep << endl); // Use findIdUpward instead of findIdFlat; it doesn't matter for now @@ -246,14 +246,14 @@ private: // Note cannot do modport resolution here; modports are allowed underneath generates } - virtual void visit(AstPackageImport* nodep) override { + void visit(AstPackageImport* nodep) override { // Package Import: We need to do the package before the use of a package iterateChildren(nodep); UASSERT_OBJ(nodep->packagep(), nodep, "Unlinked package"); // Parser should set packagep new V3GraphEdge(&m_graph, vertex(m_modp), vertex(nodep->packagep()), 1, false); } - virtual void visit(AstBind* nodep) override { + void visit(AstBind* nodep) override { // Bind: Has cells underneath that need to be put into the new // module, and cells which need resolution // TODO this doesn't allow bind to dotted hier names, that would require @@ -268,14 +268,14 @@ private: { m_modp = modp; // Important that this adds to end, as next iterate assumes does all cells - modp->addStmtp(cellsp); + modp->addStmtsp(cellsp); iterateAndNextNull(cellsp); } } pushDeletep(nodep->unlinkFrBack()); } - virtual void visit(AstCell* nodep) override { + void visit(AstCell* nodep) override { // Cell: Resolve its filename. If necessary, parse it. // Execute only once. Complication is that cloning may result in // user1 being set (for pre-clone) so check if user1() matches the @@ -321,7 +321,7 @@ private: otherModp->recursiveClone(true); // user1 etc will retain its pre-clone value cellmodp->user2p(otherModp); - v3Global.rootp()->addModulep(otherModp); + v3Global.rootp()->addModulesp(otherModp); new V3GraphEdge(&m_graph, vertex(cellmodp), vertex(otherModp), 1, false); } @@ -452,14 +452,14 @@ private: UINFO(4, " Link Cell done: " << nodep << endl); } - virtual void visit(AstRefDType* nodep) override { + void visit(AstRefDType* nodep) override { iterateChildren(nodep); for (AstPin* pinp = nodep->paramsp(); pinp; pinp = VN_AS(pinp->nextp(), Pin)) { pinp->param(true); if (pinp->name() == "") pinp->name("__paramNumber" + cvtToStr(pinp->pinNum())); } } - virtual void visit(AstClassOrPackageRef* nodep) override { + void visit(AstClassOrPackageRef* nodep) override { iterateChildren(nodep); // Inside a class, an extends or reference to another class // Note we don't add a V3GraphEdge{vertex(m_modp), vertex(nodep->classOrPackagep()} @@ -471,7 +471,7 @@ private: } } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } // METHODS void readModNames() { @@ -528,7 +528,7 @@ public: } iterate(nodep); } - virtual ~LinkCellsVisitor() override = default; + ~LinkCellsVisitor() override = default; }; //###################################################################### diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 02e6b439b..75681218f 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -76,30 +76,32 @@ #include #include -//###################################################################### -// Matcher classes (for suggestion matching) +VL_DEFINE_DEBUG_FUNCTIONS; + +// ###################################################################### +// Matcher classes (for suggestion matching) class LinkNodeMatcherClass final : public VNodeMatcher { public: - virtual bool nodeMatch(const AstNode* nodep) const override { return VN_IS(nodep, Class); } + bool nodeMatch(const AstNode* nodep) const override { return VN_IS(nodep, Class); } }; class LinkNodeMatcherFTask final : public VNodeMatcher { public: - virtual bool nodeMatch(const AstNode* nodep) const override { return VN_IS(nodep, NodeFTask); } + bool nodeMatch(const AstNode* nodep) const override { return VN_IS(nodep, NodeFTask); } }; class LinkNodeMatcherModport final : public VNodeMatcher { public: - virtual bool nodeMatch(const AstNode* nodep) const override { return VN_IS(nodep, Modport); } + bool nodeMatch(const AstNode* nodep) const override { return VN_IS(nodep, Modport); } }; class LinkNodeMatcherVar final : public VNodeMatcher { public: - virtual bool nodeMatch(const AstNode* nodep) const override { + bool nodeMatch(const AstNode* nodep) const override { return VN_IS(nodep, Var) || VN_IS(nodep, LambdaArgRef); } }; class LinkNodeMatcherVarIO final : public VNodeMatcher { public: - virtual bool nodeMatch(const AstNode* nodep) const override { + bool nodeMatch(const AstNode* nodep) const override { const AstVar* const varp = VN_CAST(nodep, Var); if (!varp) return false; return varp->isIO(); @@ -107,7 +109,7 @@ public: }; class LinkNodeMatcherVarParam final : public VNodeMatcher { public: - virtual bool nodeMatch(const AstNode* nodep) const override { + bool nodeMatch(const AstNode* nodep) const override { const AstVar* const varp = VN_CAST(nodep, Var); if (!varp) return false; return varp->isParam(); @@ -162,14 +164,14 @@ private: public: // METHODS - VL_DEBUG_FUNC; // Declare debug() - void dump(const string& nameComment = "linkdot", bool force = false) { - if (debug() >= 6 || force) { + + void dumpSelf(const string& nameComment = "linkdot", bool force = false) { + if (dump() >= 6 || force) { const string filename = v3Global.debugFilename(nameComment) + ".txt"; const std::unique_ptr logp{V3File::new_ofstream(filename)}; if (logp->fail()) v3fatal("Can't write " << filename); std::ostream& os = *logp; - m_syms.dump(os); + m_syms.dumpSelf(os); bool first = true; for (int samn = 0; samn < SAMN__MAX; ++samn) { if (!m_scopeAliasMap[samn].empty()) { @@ -191,9 +193,9 @@ public: } void preErrorDump() { static bool diddump = false; - if (!diddump && v3Global.opt.dumpTree()) { + if (!diddump && dumpTree()) { diddump = true; - dump("linkdot-preerr", true); + dumpSelf("linkdot-preerr", true); v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkdot-preerr.tree")); } } @@ -726,8 +728,6 @@ class LinkDotFindVisitor final : public VNVisitor { int m_modWithNum = 0; // With block number, 0=none seen // METHODS - static int debug() { return LinkDotState::debug(); } - void makeImplicitNew(AstClass* nodep) { AstFunc* const newp = new AstFunc(nodep->fileline(), "new", nullptr, nullptr); newp->isConstructor(true); @@ -742,7 +742,7 @@ class LinkDotFindVisitor final : public VNVisitor { } // VISITs - virtual void visit(AstNetlist* nodep) override { + void visit(AstNetlist* nodep) override { // Process $unit or other packages // Not needed - dotted references not allowed from inside packages // for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); @@ -770,9 +770,9 @@ class LinkDotFindVisitor final : public VNVisitor { m_curSymp = m_modSymp = nullptr; } } - virtual void visit(AstTypeTable*) override {} - virtual void visit(AstConstPool*) override {} - virtual void visit(AstNodeModule* nodep) override { + void visit(AstTypeTable*) override {} + void visit(AstConstPool*) override {} + void visit(AstNodeModule* nodep) override { // Called on top module from Netlist, other modules from the cell creating them, // and packages UINFO(8, " " << nodep << endl); @@ -839,7 +839,7 @@ class LinkDotFindVisitor final : public VNVisitor { UINFO(5, "Module not under any CELL or top - dead module: " << nodep << endl); } } - virtual void visit(AstClass* nodep) override { + void visit(AstClass* nodep) override { UASSERT_OBJ(m_curSymp, nodep, "Class not under module/package/$unit"); UINFO(8, " " << nodep << endl); VL_RESTORER(m_scope); @@ -871,12 +871,12 @@ class LinkDotFindVisitor final : public VNVisitor { if (!m_explicitNew && m_statep->forPrimary()) makeImplicitNew(nodep); } } - virtual void visit(AstScope* nodep) override { + void visit(AstScope* nodep) override { UASSERT_OBJ(m_statep->forScopeCreation(), nodep, "Scopes should only exist right after V3Scope"); // Ignored. Processed in next step } - virtual void visit(AstCell* nodep) override { + void visit(AstCell* nodep) override { UINFO(5, " CELL under " << m_scope << " is " << nodep << endl); // Process XREFs/etc inside pins if (nodep->recursive() && m_inRecursion) return; @@ -911,7 +911,7 @@ class LinkDotFindVisitor final : public VNVisitor { if (nodep->modp()) iterate(nodep->modp()); } } - virtual void visit(AstCellInline* nodep) override { + void visit(AstCellInline* nodep) override { UINFO(5, " CELLINLINE under " << m_scope << " is " << nodep << endl); VSymEnt* aboveSymp = m_curSymp; // If baz__DOT__foo__DOT__bar, we need to find baz__DOT__foo and add bar to it. @@ -919,7 +919,7 @@ class LinkDotFindVisitor final : public VNVisitor { string::size_type pos; if ((pos = dottedname.rfind("__DOT__")) != string::npos) { const string dotted = dottedname.substr(0, pos); - const string ident = dottedname.substr(pos + strlen("__DOT__")); + const string ident = dottedname.substr(pos + std::strlen("__DOT__")); string baddot; VSymEnt* okSymp; aboveSymp = m_statep->findDotted(nodep->fileline(), aboveSymp, dotted, baddot, okSymp); @@ -931,11 +931,11 @@ class LinkDotFindVisitor final : public VNVisitor { m_statep->insertInline(aboveSymp, m_modSymp, nodep, nodep->name()); } } - virtual void visit(AstDefParam* nodep) override { + void visit(AstDefParam* nodep) override { nodep->user1p(m_curSymp); iterateChildren(nodep); } - virtual void visit(AstNodeBlock* nodep) override { + void visit(AstNodeBlock* nodep) override { UINFO(5, " " << nodep << endl); if (nodep->name() == "" && nodep->unnamed()) { // Unnamed blocks are only important when they contain var @@ -967,7 +967,7 @@ class LinkDotFindVisitor final : public VNVisitor { } } } - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstNodeFTask* nodep) override { // NodeTask: Remember its name for later resolution UINFO(5, " " << nodep << endl); UASSERT_OBJ(m_curSymp && m_modSymp, nodep, "Function/Task not under module?"); @@ -994,7 +994,7 @@ class LinkDotFindVisitor final : public VNVisitor { if (!nodep->isExternDef()) { // Move it to proper spot under the target class nodep->unlinkFrBack(); - classp->addStmtp(nodep); + classp->addStmtsp(nodep); nodep->isExternDef(true); // So we check there's a matching extern nodep->classOrPackagep()->unlinkFrBack()->deleteTree(); } @@ -1024,13 +1024,13 @@ class LinkDotFindVisitor final : public VNVisitor { } AstVar* const newvarp = new AstVar(nodep->fileline(), VVarType::VAR, nodep->name(), - VFlagChildDType(), dtypep); // Not dtype resolved yet + VFlagChildDType{}, dtypep); // Not dtype resolved yet newvarp->direction(VDirection::OUTPUT); newvarp->lifetime(VLifetime::AUTOMATIC); newvarp->funcReturn(true); newvarp->trace(false); // Not user visible newvarp->attrIsolateAssign(nodep->attrIsolateAssign()); - nodep->addFvarp(newvarp); + nodep->fvarp(newvarp); // Explicit insert required, as the var name shadows the upper level's task name m_statep->insertSym(m_curSymp, newvarp->name(), newvarp, nullptr /*classOrPackagep*/); @@ -1040,7 +1040,7 @@ class LinkDotFindVisitor final : public VNVisitor { m_ftaskp = nullptr; } } - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { // Var: Remember its name for later resolution UASSERT_OBJ(m_curSymp && m_modSymp, nodep, "Var not under module?"); iterateChildren(nodep); @@ -1139,8 +1139,8 @@ class LinkDotFindVisitor final : public VNVisitor { // We first search if the parameter is overwritten and then replace it with a // new value. It will keep the same FileLine information. if (v3Global.opt.hasParameter(nodep->name())) { - AstVar* const newp = new AstVar( - nodep->fileline(), VVarType(VVarType::GPARAM), nodep->name(), nodep); + AstVar* const newp = new AstVar{ + nodep->fileline(), VVarType{VVarType::GPARAM}, nodep->name(), nodep}; newp->combineType(nodep); const string svalue = v3Global.opt.parameter(nodep->name()); if (AstNode* const valuep @@ -1173,18 +1173,18 @@ class LinkDotFindVisitor final : public VNVisitor { } } } - virtual void visit(AstTypedef* nodep) override { + void visit(AstTypedef* nodep) override { UASSERT_OBJ(m_curSymp, nodep, "Typedef not under module/package/$unit"); iterateChildren(nodep); m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_classOrPackagep); } - virtual void visit(AstTypedefFwd* nodep) override { + void visit(AstTypedefFwd* nodep) override { UASSERT_OBJ(m_curSymp, nodep, "Typedef not under module/package/$unit"); iterateChildren(nodep); // No need to insert, only the real typedef matters, but need to track for errors nodep->user1p(m_curSymp); } - virtual void visit(AstParamTypeDType* nodep) override { + void visit(AstParamTypeDType* nodep) override { UASSERT_OBJ(m_curSymp, nodep, "Parameter type not under module/package/$unit"); iterateChildren(nodep); m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_classOrPackagep); @@ -1195,11 +1195,11 @@ class LinkDotFindVisitor final : public VNVisitor { symp->exported(false); } } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { // For dotted resolution, ignore all AstVars under functions, otherwise shouldn't exist UASSERT_OBJ(!m_statep->forScopeCreation(), nodep, "No CFuncs expected in tree yet"); } - virtual void visit(AstEnumItem* nodep) override { + void visit(AstEnumItem* nodep) override { // EnumItem: Remember its name for later resolution iterateChildren(nodep); // Find under either a task or the module's vars @@ -1238,7 +1238,7 @@ class LinkDotFindVisitor final : public VNVisitor { } if (ins) m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_classOrPackagep); } - virtual void visit(AstPackageImport* nodep) override { + void visit(AstPackageImport* nodep) override { UINFO(4, " Link: " << nodep << endl); VSymEnt* const srcp = m_statep->getNodeSym(nodep->packagep()); if (nodep->name() == "*") { @@ -1256,7 +1256,7 @@ class LinkDotFindVisitor final : public VNVisitor { UINFO(9, " Link Done: " << nodep << endl); // No longer needed, but can't delete until any multi-instantiated modules are expanded } - virtual void visit(AstPackageExport* nodep) override { + void visit(AstPackageExport* nodep) override { UINFO(9, " Link: " << nodep << endl); VSymEnt* const srcp = m_statep->getNodeSym(nodep->packagep()); if (nodep->name() != "*") { @@ -1270,13 +1270,13 @@ class LinkDotFindVisitor final : public VNVisitor { UINFO(9, " Link Done: " << nodep << endl); // No longer needed, but can't delete until any multi-instantiated modules are expanded } - virtual void visit(AstPackageExportStarStar* nodep) override { + void visit(AstPackageExportStarStar* nodep) override { UINFO(4, " Link: " << nodep << endl); m_curSymp->exportStarStar(m_statep->symsp()); // No longer needed, but can't delete until any multi-instantiated modules are expanded } - virtual void visit(AstForeach* nodep) override { + void visit(AstForeach* nodep) override { // Symbol table needs nodep->name() as the index variable's name VL_RESTORER(m_curSymp); VSymEnt* const oldCurSymp = m_curSymp; @@ -1327,7 +1327,7 @@ class LinkDotFindVisitor final : public VNVisitor { } } - virtual void visit(AstWithParse* nodep) override { + void visit(AstWithParse* nodep) override { // Change WITHPARSE(FUNCREF, equation) to FUNCREF(WITH(equation)) const auto funcrefp = VN_AS(nodep->funcrefp(), NodeFTaskRef); UASSERT_OBJ(funcrefp, nodep, "'with' only can operate on a function/task"); @@ -1355,7 +1355,7 @@ class LinkDotFindVisitor final : public VNVisitor { nodep->replaceWith(funcrefp->unlinkFrBack()); VL_DO_DANGLING(nodep->deleteTree(), nodep); } - virtual void visit(AstWith* nodep) override { + void visit(AstWith* nodep) override { // Symbol table needs nodep->name() as the index variable's name // Iteration will pickup the AstVar we made under AstWith VL_RESTORER(m_curSymp); @@ -1373,7 +1373,7 @@ class LinkDotFindVisitor final : public VNVisitor { } } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -1383,7 +1383,7 @@ public: iterate(rootp); } - virtual ~LinkDotFindVisitor() override = default; + ~LinkDotFindVisitor() override = default; }; //====================================================================== @@ -1400,8 +1400,6 @@ private: LinkDotState* const m_statep; // State to pass between visitors, including symbol table AstNodeModule* m_modp = nullptr; // Current module - static int debug() { return LinkDotState::debug(); } - void pinImplicitExprRecurse(AstNode* nodep) { // Under a pin, Check interconnect expression for a pin reference or a concat. // Create implicit variable as needed @@ -1425,9 +1423,9 @@ private: } // VISITs - virtual void visit(AstTypeTable*) override {} - virtual void visit(AstConstPool*) override {} - virtual void visit(AstNodeModule* nodep) override { + void visit(AstTypeTable*) override {} + void visit(AstConstPool*) override {} + void visit(AstNodeModule* nodep) override { UINFO(5, " " << nodep << endl); if (nodep->dead() || !nodep->user4()) { UINFO(4, "Mark dead module " << nodep << endl); @@ -1444,7 +1442,7 @@ private: m_modp = nullptr; } } - virtual void visit(AstPin* nodep) override { + void visit(AstPin* nodep) override { // Pin: Link to submodule's port // Deal with implicit definitions - do before Resolve visitor as may // be referenced above declaration @@ -1453,7 +1451,7 @@ private: pinImplicitExprRecurse(nodep->exprp()); } } - virtual void visit(AstDefParam* nodep) override { + void visit(AstDefParam* nodep) override { iterateChildren(nodep); nodep->v3warn(DEFPARAM, "defparam is deprecated (IEEE 1800-2017 C.4.1)\n" << nodep->warnMore() @@ -1475,7 +1473,7 @@ private: } VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } - virtual void visit(AstPort* nodep) override { + void visit(AstPort* nodep) override { // Port: Stash the pin number // Need to set pin numbers after varnames are created // But before we do the final resolution based on names @@ -1508,14 +1506,14 @@ private: // Ports not needed any more VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } - virtual void visit(AstAssignW* nodep) override { + void visit(AstAssignW* nodep) override { // Deal with implicit definitions // We used to nodep->allowImplicit() here, but it turns out // normal "assigns" can also make implicit wires. Yuk. pinImplicitExprRecurse(nodep->lhsp()); iterateChildren(nodep); } - virtual void visit(AstAssignAlias* nodep) override { + void visit(AstAssignAlias* nodep) override { // tran gates need implicit creation // As VarRefs don't exist in forPrimary, sanity check UASSERT_OBJ(!m_statep->forPrimary(), nodep, "Assign aliases unexpected pre-dot"); @@ -1527,13 +1525,13 @@ private: } iterateChildren(nodep); } - virtual void visit(AstImplicit* nodep) override { + void visit(AstImplicit* nodep) override { // Unsupported gates need implicit creation pinImplicitExprRecurse(nodep); // We're done with implicit gates VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } - virtual void visit(AstClassOrPackageRef* nodep) override { + void visit(AstClassOrPackageRef* nodep) override { if (auto* const fwdp = VN_CAST(nodep->classOrPackageNodep(), TypedefFwd)) { // Relink forward definitions to the "real" definition VSymEnt* const foundp = m_statep->getNodeSym(fwdp)->findIdFallback(fwdp->name()); @@ -1555,7 +1553,7 @@ private: } iterateChildren(nodep); } - virtual void visit(AstTypedefFwd* nodep) override { + void visit(AstTypedefFwd* nodep) override { VSymEnt* const foundp = m_statep->getNodeSym(nodep)->findIdFallback(nodep->name()); if (!foundp && v3Global.opt.pedantic()) { // We only check it was ever really defined in pedantic mode, as it @@ -1570,7 +1568,7 @@ private: VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -1579,7 +1577,7 @@ public: UINFO(4, __FUNCTION__ << ": " << endl); iterate(rootp); } - virtual ~LinkDotParamVisitor() override = default; + ~LinkDotParamVisitor() override = default; }; //====================================================================== @@ -1591,15 +1589,13 @@ class LinkDotScopeVisitor final : public VNVisitor { const AstScope* m_scopep = nullptr; // The current scope VSymEnt* m_modSymp = nullptr; // Symbol entry for current module - static int debug() { return LinkDotState::debug(); } - // VISITs - virtual void visit(AstNetlist* nodep) override { + void visit(AstNetlist* nodep) override { // Recurse..., backward as must do packages before using packages iterateChildrenBackwards(nodep); } - virtual void visit(AstConstPool*) override {} - virtual void visit(AstScope* nodep) override { + void visit(AstConstPool*) override {} + void visit(AstScope* nodep) override { UINFO(8, " SCOPE " << nodep << endl); UASSERT_OBJ(m_statep->forScopeCreation(), nodep, "Scopes should only exist right after V3Scope"); @@ -1611,7 +1607,7 @@ class LinkDotScopeVisitor final : public VNVisitor { m_modSymp = nullptr; m_scopep = nullptr; } - virtual void visit(AstVarScope* nodep) override { + void visit(AstVarScope* nodep) override { if (!nodep->varp()->isFuncLocal() && !nodep->varp()->isClassMember()) { VSymEnt* const varSymp = m_statep->insertSym(m_modSymp, nodep->varp()->name(), nodep, nullptr); @@ -1649,22 +1645,22 @@ class LinkDotScopeVisitor final : public VNVisitor { } } } - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstNodeFTask* nodep) override { VSymEnt* const symp = m_statep->insertBlock(m_modSymp, nodep->name(), nodep, nullptr); symp->fallbackp(m_modSymp); // No recursion, we don't want to pick up variables } - virtual void visit(AstForeach* nodep) override { + void visit(AstForeach* nodep) override { VSymEnt* const symp = m_statep->insertBlock(m_modSymp, nodep->name(), nodep, nullptr); symp->fallbackp(m_modSymp); // No recursion, we don't want to pick up variables } - virtual void visit(AstWith* nodep) override { + void visit(AstWith* nodep) override { VSymEnt* const symp = m_statep->insertBlock(m_modSymp, nodep->name(), nodep, nullptr); symp->fallbackp(m_modSymp); // No recursion, we don't want to pick up variables } - virtual void visit(AstAssignAlias* nodep) override { + void visit(AstAssignAlias* nodep) override { // Track aliases created by V3Inline; if we get a VARXREF(aliased_from) // we'll need to replace it with a VARXREF(aliased_to) if (debug() >= 9) nodep->dumpTree(cout, "- alias: "); @@ -1674,7 +1670,7 @@ class LinkDotScopeVisitor final : public VNVisitor { fromVscp->user2p(toVscp); iterateChildren(nodep); } - virtual void visit(AstAssignVarScope* nodep) override { + void visit(AstAssignVarScope* nodep) override { UINFO(5, "ASSIGNVARSCOPE " << nodep << endl); if (debug() >= 9) nodep->dumpTree(cout, "- avs: "); VSymEnt* rhsSymp; @@ -1734,9 +1730,9 @@ class LinkDotScopeVisitor final : public VNVisitor { } // For speed, don't recurse things that can't have scope // Note we allow AstNodeStmt's as generates may be under them - virtual void visit(AstCell*) override {} - virtual void visit(AstVar*) override {} - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstCell*) override {} + void visit(AstVar*) override {} + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -1745,7 +1741,7 @@ public: UINFO(4, __FUNCTION__ << ": " << endl); iterate(rootp); } - virtual ~LinkDotScopeVisitor() override = default; + ~LinkDotScopeVisitor() override = default; }; //====================================================================== @@ -1756,11 +1752,8 @@ class LinkDotIfaceVisitor final : public VNVisitor { LinkDotState* const m_statep; // State to pass between visitors, including symbol table VSymEnt* m_curSymp; // Symbol Entry for current table, where to lookup/insert - // METHODS - static int debug() { return LinkDotState::debug(); } - // VISITs - virtual void visit(AstModport* nodep) override { + void visit(AstModport* nodep) override { // Modport: Remember its name for later resolution UINFO(5, " fiv: " << nodep << endl); VL_RESTORER(m_curSymp); @@ -1772,7 +1765,7 @@ class LinkDotIfaceVisitor final : public VNVisitor { iterateChildren(nodep); } } - virtual void visit(AstModportFTaskRef* nodep) override { + void visit(AstModportFTaskRef* nodep) override { UINFO(5, " fif: " << nodep << endl); iterateChildren(nodep); if (nodep->isExport()) nodep->v3warn(E_UNSUPPORTED, "Unsupported: modport export"); @@ -1795,7 +1788,7 @@ class LinkDotIfaceVisitor final : public VNVisitor { VL_DO_DANGLING(pushDeletep(nodep), nodep); } } - virtual void visit(AstModportVarRef* nodep) override { + void visit(AstModportVarRef* nodep) override { UINFO(5, " fiv: " << nodep << endl); iterateChildren(nodep); VSymEnt* const symp = m_curSymp->findIdFallback(nodep->name()); @@ -1820,7 +1813,7 @@ class LinkDotIfaceVisitor final : public VNVisitor { VL_DO_DANGLING(pushDeletep(nodep), nodep); } } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -1830,7 +1823,7 @@ public: UINFO(4, __FUNCTION__ << ": " << endl); iterate(nodep); } - virtual ~LinkDotIfaceVisitor() override = default; + ~LinkDotIfaceVisitor() override = default; }; void LinkDotState::computeIfaceModSyms() { @@ -1906,8 +1899,6 @@ private: } } m_ds; // State to preserve across recursions - static int debug() { return LinkDotState::debug(); } - // METHODS - Variables void createImplicitVar(VSymEnt* /*lookupSymp*/, AstVarRef* nodep, AstNodeModule* modp, VSymEnt* moduleSymp, bool noWarn) { @@ -1935,10 +1926,10 @@ private: } } AstVar* const newp = new AstVar(nodep->fileline(), VVarType::WIRE, nodep->name(), - VFlagLogicPacked(), 1); + VFlagLogicPacked{}, 1); newp->trace(modp->modTrace()); nodep->varp(newp); - modp->addStmtp(newp); + modp->addStmtsp(newp); // Link it to signal list, must add the variable under the module; // current scope might be lower now m_statep->insertSym(moduleSymp, newp->name(), newp, nullptr /*classOrPackagep*/); @@ -1966,7 +1957,7 @@ private: nodep->v3error("Illegal call of a task as a function: " << nodep->prettyNameQ()); } } - inline void checkNoDot(AstNode* nodep) { + void checkNoDot(AstNode* nodep) { if (VL_UNLIKELY(m_ds.m_dotPos != DP_NONE)) { // UINFO(9, "ds=" << m_ds.ascii() << endl); nodep->v3error("Syntax Error: Not expecting " << nodep->type() << " under a " @@ -2005,13 +1996,13 @@ private: } // VISITs - virtual void visit(AstNetlist* nodep) override { + void visit(AstNetlist* nodep) override { // Recurse..., backward as must do packages before using packages iterateChildrenBackwards(nodep); } - virtual void visit(AstTypeTable*) override {} - virtual void visit(AstConstPool*) override {} - virtual void visit(AstNodeModule* nodep) override { + void visit(AstTypeTable*) override {} + void visit(AstConstPool*) override {} + void visit(AstNodeModule* nodep) override { if (nodep->dead()) return; checkNoDot(nodep); UINFO(8, " " << nodep << endl); @@ -2025,7 +2016,7 @@ private: m_modp = nullptr; m_ds.m_dotSymp = m_curSymp = m_modSymp = nullptr; } - virtual void visit(AstScope* nodep) override { + void visit(AstScope* nodep) override { UINFO(8, " " << nodep << endl); VL_RESTORER(m_modSymp); VL_RESTORER(m_curSymp); @@ -2036,14 +2027,14 @@ private: m_ds.m_dotSymp = m_curSymp = m_modSymp = nullptr; } } - virtual void visit(AstCellInline* nodep) override { + void visit(AstCellInline* nodep) override { checkNoDot(nodep); if (m_statep->forScopeCreation() && !v3Global.opt.vpi()) { nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); } } - virtual void visit(AstCell* nodep) override { + void visit(AstCell* nodep) override { // Cell: Recurse inside or cleanup not founds checkNoDot(nodep); AstNode::user5ClearTree(); @@ -2072,7 +2063,7 @@ private: // Parent module inherits child's publicity // This is done bottom up in the LinkBotupVisitor stage } - virtual void visit(AstClassRefDType* nodep) override { + void visit(AstClassRefDType* nodep) override { // Cell: Recurse inside or cleanup not founds checkNoDot(nodep); AstNode::user5ClearTree(); @@ -2089,7 +2080,7 @@ private: iterateChildren(nodep); } } - virtual void visit(AstPin* nodep) override { + void visit(AstPin* nodep) override { // Pin: Link to submodule's port checkNoDot(nodep); iterateChildren(nodep); @@ -2130,7 +2121,7 @@ private: } // Early return() above when deleted } - virtual void visit(AstDot* nodep) override { + void visit(AstDot* nodep) override { // Legal under a DOT: AstDot, AstParseRef, AstPackageRef, AstNodeSel // also a DOT can be part of an expression, but only above plus // AstFTaskRef are legal children @@ -2239,7 +2230,7 @@ private: m_ds.m_dotp = lastStates.m_dotp; } } - virtual void visit(AstParseRef* nodep) override { + void visit(AstParseRef* nodep) override { if (nodep->user3SetOnce()) return; UINFO(9, " linkPARSEREF " << m_ds.ascii() << " n=" << nodep << endl); // m_curSymp is symbol table of outer expression @@ -2509,7 +2500,7 @@ private: UINFO(7, " ErrParseRef curSymp=se" << cvtToHex(m_curSymp) << " ds=" << m_ds.ascii() << endl); const string suggest = m_statep->suggestSymFallback( - m_ds.m_dotSymp, nodep->name(), VNodeMatcher()); + m_ds.m_dotSymp, nodep->name(), VNodeMatcher{}); nodep->v3error("Can't find definition of " << expectWhat << ": " << nodep->prettyNameQ() << '\n' << (suggest.empty() ? "" : nodep->warnMore() + suggest)); @@ -2538,7 +2529,7 @@ private: } if (start) m_ds = lastStates; } - virtual void visit(AstClassOrPackageRef* nodep) override { + void visit(AstClassOrPackageRef* nodep) override { // Class: Recurse inside or cleanup not founds // checkNoDot not appropriate, can be under a dot AstNode::user5ClearTree(); @@ -2559,7 +2550,7 @@ private: } } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { // VarRef: Resolve its reference // ParseRefs are used the first pass (forPrimary) so we shouldn't get can't find // errors here now that we have a VarRef. @@ -2581,7 +2572,7 @@ private: } } } - virtual void visit(AstVarXRef* nodep) override { + void visit(AstVarXRef* nodep) override { // VarRef: Resolve its reference // We always link even if varp() is set, because the module we choose may change // due to creating new modules, flattening, etc. @@ -2661,18 +2652,18 @@ private: } } } - virtual void visit(AstEnumDType* nodep) override { + void visit(AstEnumDType* nodep) override { iterateChildren(nodep); AstRefDType* const refdtypep = VN_CAST(nodep->subDTypep(), RefDType); if (refdtypep && (nodep == refdtypep->subDTypep())) { refdtypep->v3error("Self-referential enumerated type definition"); } } - virtual void visit(AstEnumItemRef* nodep) override { + void visit(AstEnumItemRef* nodep) override { // EnumItemRef may be under a dot. Should already be resolved. iterateChildren(nodep); } - virtual void visit(AstMethodCall* nodep) override { + void visit(AstMethodCall* nodep) override { // Created here so should already be resolved. VL_RESTORER(m_ds); { @@ -2680,7 +2671,7 @@ private: iterateChildren(nodep); } } - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { checkNoDot(nodep); iterateChildren(nodep); if (m_statep->forPrimary() && nodep->isIO() && !m_ftaskp && !nodep->user4()) { @@ -2688,7 +2679,7 @@ private: "Input/output/inout does not appear in port list: " << nodep->prettyNameQ()); } } - virtual void visit(AstNodeFTaskRef* nodep) override { + void visit(AstNodeFTaskRef* nodep) override { if (nodep->user3SetOnce()) return; UINFO(8, " " << nodep << endl); UINFO(8, " " << m_ds.ascii() << endl); @@ -2854,7 +2845,7 @@ private: iterateChildren(nodep); } } - virtual void visit(AstSelBit* nodep) override { + void visit(AstSelBit* nodep) override { if (nodep->user3SetOnce()) return; iterateAndNextNull(nodep->fromp()); if (m_ds.m_dotPos @@ -2882,7 +2873,7 @@ private: VL_DO_DANGLING(pushDeletep(nodep), nodep); } } - virtual void visit(AstNodePreSel* nodep) override { + void visit(AstNodePreSel* nodep) override { // Excludes simple AstSelBit, see above if (nodep->user3SetOnce()) return; if (m_ds.m_dotPos @@ -2901,11 +2892,11 @@ private: iterateAndNextNull(nodep->attrp()); } } - virtual void visit(AstMemberSel* nodep) override { + void visit(AstMemberSel* nodep) override { // checkNoDot not appropriate, can be under a dot iterateChildren(nodep); } - virtual void visit(AstNodeBlock* nodep) override { + void visit(AstNodeBlock* nodep) override { UINFO(5, " " << nodep << endl); checkNoDot(nodep); VSymEnt* const oldCurSymp = m_curSymp; @@ -2919,7 +2910,7 @@ private: m_ds.m_dotSymp = m_curSymp = oldCurSymp; UINFO(5, " cur=se" << cvtToHex(m_curSymp) << endl); } - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstNodeFTask* nodep) override { UINFO(5, " " << nodep << endl); checkNoDot(nodep); if (nodep->isExternDef()) { @@ -2941,7 +2932,7 @@ private: m_ds.m_dotSymp = m_curSymp = oldCurSymp; m_ftaskp = nullptr; } - virtual void visit(AstForeach* nodep) override { + void visit(AstForeach* nodep) override { UINFO(5, " " << nodep << endl); checkNoDot(nodep); VSymEnt* const oldCurSymp = m_curSymp; @@ -2951,7 +2942,7 @@ private: } m_ds.m_dotSymp = m_curSymp = oldCurSymp; } - virtual void visit(AstWith* nodep) override { + void visit(AstWith* nodep) override { UINFO(5, " " << nodep << endl); checkNoDot(nodep); VSymEnt* const oldCurSymp = m_curSymp; @@ -2961,12 +2952,12 @@ private: } m_ds.m_dotSymp = m_curSymp = oldCurSymp; } - virtual void visit(AstLambdaArgRef* nodep) override { + void visit(AstLambdaArgRef* nodep) override { UINFO(5, " " << nodep << endl); // No checknodot(nodep), visit(AstScope) will check for LambdaArgRef iterateChildren(nodep); } - virtual void visit(AstClass* nodep) override { + void visit(AstClass* nodep) override { UINFO(5, " " << nodep << endl); checkNoDot(nodep); VL_RESTORER(m_curSymp); @@ -3041,7 +3032,7 @@ private: } } } - virtual void visit(AstRefDType* nodep) override { + void visit(AstRefDType* nodep) override { // Resolve its reference if (nodep->user3SetOnce()) return; if (AstNode* const cpackagep = nodep->classOrPackageOpp()) { @@ -3097,7 +3088,7 @@ private: nodep->classOrPackagep(foundp->classOrPackagep()); } } else if (AstClass* const defp = foundp ? VN_AS(foundp->nodep(), Class) : nullptr) { - AstNode* const paramsp = nodep->paramsp(); + AstPin* const paramsp = nodep->paramsp(); if (paramsp) paramsp->unlinkFrBackWithNext(); AstClassRefDType* const newp = new AstClassRefDType{nodep->fileline(), defp, paramsp}; @@ -3112,7 +3103,7 @@ private: } iterateChildren(nodep); } - virtual void visit(AstDpiExport* nodep) override { + void visit(AstDpiExport* nodep) override { // AstDpiExport: Make sure the function referenced exists, then dump it iterateChildren(nodep); checkNoDot(nodep); @@ -3130,35 +3121,35 @@ private: } VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } - virtual void visit(AstPackageImport* nodep) override { + void visit(AstPackageImport* nodep) override { // No longer needed checkNoDot(nodep); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } - virtual void visit(AstPackageExport* nodep) override { + void visit(AstPackageExport* nodep) override { // No longer needed checkNoDot(nodep); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } - virtual void visit(AstPackageExportStarStar* nodep) override { + void visit(AstPackageExportStarStar* nodep) override { // No longer needed checkNoDot(nodep); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } - virtual void visit(AstCellRef* nodep) override { + void visit(AstCellRef* nodep) override { UINFO(5, " AstCellRef: " << nodep << " " << m_ds.ascii() << endl); iterateChildren(nodep); } - virtual void visit(AstCellArrayRef* nodep) override { + void visit(AstCellArrayRef* nodep) override { UINFO(5, " AstCellArrayRef: " << nodep << " " << m_ds.ascii() << endl); // Expression already iterated } - virtual void visit(AstUnlinkedRef* nodep) override { + void visit(AstUnlinkedRef* nodep) override { UINFO(5, " AstCellArrayRef: " << nodep << " " << m_ds.ascii() << endl); // No need to iterate, if we have a UnlinkedVarXRef, we're already done } - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { checkNoDot(nodep); iterateChildren(nodep); } @@ -3170,27 +3161,25 @@ public: UINFO(4, __FUNCTION__ << ": " << endl); iterate(rootp); } - virtual ~LinkDotResolveVisitor() override = default; + ~LinkDotResolveVisitor() override = default; }; //###################################################################### // Link class functions -int V3LinkDot::debug() { return LinkDotState::debug(); } - void V3LinkDot::linkDotGuts(AstNetlist* rootp, VLinkDotStep step) { - if (LinkDotState::debug() >= 5 || v3Global.opt.dumpTree() >= 9) { + if (debug() >= 5 || dumpTree() >= 9) { v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot.tree")); } LinkDotState state(rootp, step); const LinkDotFindVisitor visitor{rootp, &state}; - if (LinkDotState::debug() >= 5 || v3Global.opt.dumpTree() >= 9) { + if (debug() >= 5 || dumpTree() >= 9) { v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-find.tree")); } if (step == LDS_PRIMARY || step == LDS_PARAMED) { // Initial link stage, resolve parameters const LinkDotParamVisitor visitors{rootp, &state}; - if (LinkDotState::debug() >= 5 || v3Global.opt.dumpTree() >= 9) { + if (debug() >= 5 || dumpTree() >= 9) { v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-param.tree")); } } else if (step == LDS_ARRAYED) { @@ -3199,16 +3188,40 @@ void V3LinkDot::linkDotGuts(AstNetlist* rootp, VLinkDotStep step) { // process AstScope's. This needs to be separate pass after whole hierarchy graph created. const LinkDotScopeVisitor visitors{rootp, &state}; v3Global.assertScoped(true); - if (LinkDotState::debug() >= 5 || v3Global.opt.dumpTree() >= 9) { + if (debug() >= 5 || dumpTree() >= 9) { v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-scoped.tree")); } } else { v3fatalSrc("Bad case"); } - state.dump(); + state.dumpSelf(); state.computeIfaceModSyms(); state.computeIfaceVarSyms(); state.computeScopeAliases(); - state.dump(); + state.dumpSelf(); { LinkDotResolveVisitor{rootp, &state}; } } + +void V3LinkDot::linkDotPrimary(AstNetlist* nodep) { + UINFO(2, __FUNCTION__ << ": " << endl); + linkDotGuts(nodep, LDS_PRIMARY); + V3Global::dumpCheckGlobalTree("linkdot", 0, dumpTree() >= 6); +} + +void V3LinkDot::linkDotParamed(AstNetlist* nodep) { + UINFO(2, __FUNCTION__ << ": " << endl); + linkDotGuts(nodep, LDS_PARAMED); + V3Global::dumpCheckGlobalTree("linkdotparam", 0, dumpTree() >= 3); +} + +void V3LinkDot::linkDotArrayed(AstNetlist* nodep) { + UINFO(2, __FUNCTION__ << ": " << endl); + linkDotGuts(nodep, LDS_ARRAYED); + V3Global::dumpCheckGlobalTree("linkdot", 0, dumpTree() >= 6); +} + +void V3LinkDot::linkDotScope(AstNetlist* nodep) { + UINFO(2, __FUNCTION__ << ": " << endl); + linkDotGuts(nodep, LDS_SCOPED); + V3Global::dumpCheckGlobalTree("linkdot", 0, dumpTree() >= 3); +} diff --git a/src/V3LinkDot.h b/src/V3LinkDot.h index 260c8cbcf..428f18904 100644 --- a/src/V3LinkDot.h +++ b/src/V3LinkDot.h @@ -28,32 +28,13 @@ enum VLinkDotStep : uint8_t { LDS_PRIMARY, LDS_PARAMED, LDS_ARRAYED, LDS_SCOPED }; class V3LinkDot final { -private: - static int debug(); static void linkDotGuts(AstNetlist* rootp, VLinkDotStep step); public: - static void linkDotPrimary(AstNetlist* nodep) { - UINFO(2, __FUNCTION__ << ": " << endl); - linkDotGuts(nodep, LDS_PRIMARY); - V3Global::dumpCheckGlobalTree("linkdot", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6); - } - static void linkDotParamed(AstNetlist* nodep) { - UINFO(2, __FUNCTION__ << ": " << endl); - linkDotGuts(nodep, LDS_PARAMED); - V3Global::dumpCheckGlobalTree("linkdotparam", 0, - v3Global.opt.dumpTreeLevel(__FILE__) >= 3); - } - static void linkDotArrayed(AstNetlist* nodep) { - UINFO(2, __FUNCTION__ << ": " << endl); - linkDotGuts(nodep, LDS_ARRAYED); - V3Global::dumpCheckGlobalTree("linkdot", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6); - } - static void linkDotScope(AstNetlist* nodep) { - UINFO(2, __FUNCTION__ << ": " << endl); - linkDotGuts(nodep, LDS_SCOPED); - V3Global::dumpCheckGlobalTree("linkdot", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); - } + static void linkDotPrimary(AstNetlist* nodep); + static void linkDotParamed(AstNetlist* nodep); + static void linkDotArrayed(AstNetlist* nodep); + static void linkDotScope(AstNetlist* nodep); }; #endif // Guard diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index 66dcbf8e1..91bfbe530 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -46,6 +46,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### class LinkIncVisitor final : public VNVisitor { @@ -64,8 +66,6 @@ private: bool m_unsupportedHere = false; // Used to detect where it's not supported yet // METHODS - VL_DEBUG_FUNC; // Declare debug() - void insertBeforeStmt(AstNode* nodep, AstNode* newp) { // Return node that must be visited, if any // See also AstNode::addBeforeStmt; this predates that function @@ -89,12 +89,12 @@ private: } // VISITORS - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { VL_RESTORER(m_modIncrementsNum); m_modIncrementsNum = 0; iterateChildren(nodep); } - virtual void visit(AstWhile* nodep) override { + void visit(AstWhile* nodep) override { // Special, as statements need to be put in different places // Preconditions insert first just before themselves (the normal // rule for other statement types) @@ -106,12 +106,12 @@ private: iterateAndNextNull(nodep->condp()); // Body insert just before themselves m_insStmtp = nullptr; // First thing should be new statement - iterateAndNextNull(nodep->bodysp()); + iterateAndNextNull(nodep->stmtsp()); iterateAndNextNull(nodep->incsp()); // Done the loop m_insStmtp = nullptr; // Next thing should be new statement } - virtual void visit(AstForeach* nodep) override { + void visit(AstForeach* nodep) override { // Special, as statements need to be put in different places // Body insert just before themselves m_insStmtp = nullptr; // First thing should be new statement @@ -119,7 +119,7 @@ private: // Done the loop m_insStmtp = nullptr; // Next thing should be new statement } - virtual void visit(AstJumpBlock* nodep) override { + void visit(AstJumpBlock* nodep) override { // Special, as statements need to be put in different places // Body insert just before themselves m_insStmtp = nullptr; // First thing should be new statement @@ -127,15 +127,15 @@ private: // Done the loop m_insStmtp = nullptr; // Next thing should be new statement } - virtual void visit(AstNodeIf* nodep) override { + void visit(AstNodeIf* nodep) override { m_insStmtp = nodep; iterateAndNextNull(nodep->condp()); m_insStmtp = nullptr; - iterateAndNextNull(nodep->ifsp()); + iterateAndNextNull(nodep->thensp()); iterateAndNextNull(nodep->elsesp()); m_insStmtp = nullptr; } - virtual void visit(AstCaseItem* nodep) override { + void visit(AstCaseItem* nodep) override { m_insMode = IM_BEFORE; { VL_RESTORER(m_unsupportedHere); @@ -143,13 +143,13 @@ private: iterateAndNextNull(nodep->condsp()); } m_insStmtp = nullptr; // Next thing should be new statement - iterateAndNextNull(nodep->bodysp()); + iterateAndNextNull(nodep->stmtsp()); } - virtual void visit(AstNodeFor* nodep) override { // LCOV_EXCL_LINE + void visit(AstNodeFor* nodep) override { // LCOV_EXCL_LINE nodep->v3fatalSrc( "For statements should have been converted to while statements in V3Begin.cpp"); } - virtual void visit(AstNodeStmt* nodep) override { + void visit(AstNodeStmt* nodep) override { if (!nodep->isStatement()) { iterateChildren(nodep); return; @@ -165,11 +165,11 @@ private: UINFO(9, "Marking unsupported " << nodep << endl); iterateChildren(nodep); } - virtual void visit(AstLogAnd* nodep) override { unsupported_visit(nodep); } - virtual void visit(AstLogOr* nodep) override { unsupported_visit(nodep); } - virtual void visit(AstLogEq* nodep) override { unsupported_visit(nodep); } - virtual void visit(AstLogIf* nodep) override { unsupported_visit(nodep); } - virtual void visit(AstNodeCond* nodep) override { unsupported_visit(nodep); } + void visit(AstLogAnd* nodep) override { unsupported_visit(nodep); } + void visit(AstLogOr* nodep) override { unsupported_visit(nodep); } + void visit(AstLogEq* nodep) override { unsupported_visit(nodep); } + void visit(AstLogIf* nodep) override { unsupported_visit(nodep); } + void visit(AstNodeCond* nodep) override { unsupported_visit(nodep); } void prepost_visit(AstNodeTriop* nodep) { // Check if we are underneath a statement if (!m_insStmtp) { @@ -257,17 +257,17 @@ private: nodep->replaceWith(new AstVarRef(varrefp->fileline(), varp, VAccess::WRITE)); VL_DO_DANGLING(nodep->deleteTree(), nodep); } - virtual void visit(AstPreAdd* nodep) override { prepost_visit(nodep); } - virtual void visit(AstPostAdd* nodep) override { prepost_visit(nodep); } - virtual void visit(AstPreSub* nodep) override { prepost_visit(nodep); } - virtual void visit(AstPostSub* nodep) override { prepost_visit(nodep); } - virtual void visit(AstGenFor* nodep) override { iterateChildren(nodep); } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstPreAdd* nodep) override { prepost_visit(nodep); } + void visit(AstPostAdd* nodep) override { prepost_visit(nodep); } + void visit(AstPreSub* nodep) override { prepost_visit(nodep); } + void visit(AstPostSub* nodep) override { prepost_visit(nodep); } + void visit(AstGenFor* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit LinkIncVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~LinkIncVisitor() override = default; + ~LinkIncVisitor() override = default; }; //###################################################################### @@ -276,5 +276,5 @@ public: void V3LinkInc::linkIncrements(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { LinkIncVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("linkinc", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("linkinc", 0, dumpTree() >= 3); } diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp index 9b85ac6f6..5243ed1cb 100644 --- a/src/V3LinkJump.cpp +++ b/src/V3LinkJump.cpp @@ -40,6 +40,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### class LinkJumpVisitor final : public VNVisitor { @@ -54,8 +56,6 @@ private: std::vector m_blockStack; // All begin blocks above current node // METHODS - VL_DEBUG_FUNC; // Declare debug() - AstJumpLabel* findAddLabel(AstNode* nodep, bool endOfIter) { // Put label under given node, and if WHILE optionally at end of iteration UINFO(4, "Create label for " << nodep << endl); @@ -69,7 +69,7 @@ private: underp = VN_AS(nodep, NodeFTask)->stmtsp(); } else if (VN_IS(nodep, Foreach)) { if (endOfIter) { - underp = VN_AS(nodep, Foreach)->bodysp(); + underp = VN_AS(nodep, Foreach)->stmtsp(); } else { underp = nodep; under_and_next = false; // IE we skip the entire foreach @@ -78,7 +78,7 @@ private: if (endOfIter) { // Note we jump to end of bodysp; a FOR loop has its // increment under incsp() which we don't skip - underp = VN_AS(nodep, While)->bodysp(); + underp = VN_AS(nodep, While)->stmtsp(); } else { underp = nodep; under_and_next = false; // IE we skip the entire while @@ -122,7 +122,7 @@ private: } // VISITORS - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { if (nodep->dead()) return; VL_RESTORER(m_modp); VL_RESTORER(m_modRepeatNum); @@ -132,12 +132,12 @@ private: iterateChildren(nodep); } } - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstNodeFTask* nodep) override { m_ftaskp = nodep; iterateChildren(nodep); m_ftaskp = nullptr; } - virtual void visit(AstNodeBlock* nodep) override { + void visit(AstNodeBlock* nodep) override { UINFO(8, " " << nodep << endl); VL_RESTORER(m_inFork); m_blockStack.push_back(nodep); @@ -147,7 +147,7 @@ private: } m_blockStack.pop_back(); } - virtual void visit(AstRepeat* nodep) override { + void visit(AstRepeat* nodep) override { // So later optimizations don't need to deal with them, // REPEAT(count,body) -> loop=count,WHILE(loop>0) { body, loop-- } // Note var can be signed or unsigned based on original number. @@ -157,7 +157,7 @@ private: AstVar* const varp = new AstVar(nodep->fileline(), VVarType::BLOCKTEMP, name, nodep->findSigned32DType()); varp->usedLoopIdx(true); - m_modp->addStmtp(varp); + m_modp->addStmtsp(varp); AstNode* initsp = new AstAssign( nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::WRITE), countp); AstNode* const decp = new AstAssign( @@ -167,7 +167,7 @@ private: AstNode* const zerosp = new AstConst(nodep->fileline(), AstConst::Signed32(), 0); AstNode* const condp = new AstGtS( nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::READ), zerosp); - AstNode* const bodysp = nodep->bodysp(); + AstNode* const bodysp = nodep->stmtsp(); if (bodysp) bodysp->unlinkFrBackWithNext(); AstNode* newp = new AstWhile(nodep->fileline(), condp, bodysp, decp); initsp = initsp->addNext(newp); @@ -175,10 +175,10 @@ private: nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } - virtual void visit(AstWait* nodep) override { + void visit(AstWait* nodep) override { nodep->v3warn(E_UNSUPPORTED, "Unsupported: wait statements"); // Statements we'll just execute immediately; equivalent to if they followed this - if (AstNode* const bodysp = nodep->bodysp()) { + if (AstNode* const bodysp = nodep->stmtsp()) { bodysp->unlinkFrBackWithNext(); nodep->replaceWith(bodysp); } else { @@ -186,7 +186,7 @@ private: } VL_DO_DANGLING(nodep->deleteTree(), nodep); } - virtual void visit(AstWhile* nodep) override { + void visit(AstWhile* nodep) override { // Don't need to track AstRepeat/AstFor as they have already been converted VL_RESTORER(m_loopp); VL_RESTORER(m_loopInc); @@ -195,19 +195,19 @@ private: m_loopInc = false; iterateAndNextNull(nodep->precondsp()); iterateAndNextNull(nodep->condp()); - iterateAndNextNull(nodep->bodysp()); + iterateAndNextNull(nodep->stmtsp()); m_loopInc = true; iterateAndNextNull(nodep->incsp()); } } - virtual void visit(AstForeach* nodep) override { + void visit(AstForeach* nodep) override { VL_RESTORER(m_loopp); { m_loopp = nodep; - iterateAndNextNull(nodep->bodysp()); + iterateAndNextNull(nodep->stmtsp()); } } - virtual void visit(AstReturn* nodep) override { + void visit(AstReturn* nodep) override { iterateChildren(nodep); const AstFunc* const funcp = VN_CAST(m_ftaskp, Func); if (m_inFork) { @@ -235,7 +235,7 @@ private: nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); } - virtual void visit(AstBreak* nodep) override { + void visit(AstBreak* nodep) override { iterateChildren(nodep); if (!m_loopp) { nodep->v3error("break isn't underneath a loop"); @@ -247,7 +247,7 @@ private: nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); } - virtual void visit(AstContinue* nodep) override { + void visit(AstContinue* nodep) override { iterateChildren(nodep); if (!m_loopp) { nodep->v3error("continue isn't underneath a loop"); @@ -260,7 +260,7 @@ private: nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); } - virtual void visit(AstDisable* nodep) override { + void visit(AstDisable* nodep) override { UINFO(8, " DISABLE " << nodep << endl); iterateChildren(nodep); AstNodeBlock* blockp = nullptr; @@ -285,16 +285,16 @@ private: VL_DO_DANGLING(pushDeletep(nodep), nodep); // if (debug() >= 9) { UINFO(0, "\n"); beginp->dumpTree(cout, " labelo: "); } } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { if (m_loopInc && nodep->varp()) nodep->varp()->usedLoopIdx(true); } - virtual void visit(AstConst*) override {} - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstConst*) override {} + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit LinkJumpVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~LinkJumpVisitor() override = default; + ~LinkJumpVisitor() override = default; }; //###################################################################### @@ -303,5 +303,5 @@ public: void V3LinkJump::linkJump(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { LinkJumpVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("linkjump", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("linkjump", 0, dumpTree() >= 3); } diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp index 0e8f4ed65..d0e01d997 100644 --- a/src/V3LinkLValue.cpp +++ b/src/V3LinkLValue.cpp @@ -28,6 +28,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Link state, as a visitor of each AstNode @@ -37,20 +39,21 @@ private: // STATE bool m_setContinuously = false; // Set that var has some continuous assignment + bool m_setStrengthSpecified = false; // Set that var has assignment with strength specified. VAccess m_setRefLvalue; // Set VarRefs to lvalues for pin assignments AstNodeFTask* m_ftaskp = nullptr; // Function or task we're inside - // METHODS - VL_DEBUG_FUNC; // Declare debug() - // VISITs // Result handing - virtual void visit(AstNodeVarRef* nodep) override { + void visit(AstNodeVarRef* nodep) override { // VarRef: LValue its reference if (m_setRefLvalue != VAccess::NOCHANGE) nodep->access(m_setRefLvalue); if (nodep->varp()) { if (nodep->access().isWriteOrRW() && m_setContinuously) { nodep->varp()->isContinuously(true); + // Strength may only be specified in continuous assignment, + // so it is needed to check only if m_setContinuously is true + if (m_setStrengthSpecified) nodep->varp()->hasStrengthAssignment(true); } if (nodep->access().isWriteOrRW() && !m_ftaskp && nodep->varp()->isReadOnly()) { nodep->v3warn(ASSIGNIN, @@ -61,7 +64,7 @@ private: } // Nodes that start propagating down lvalues - virtual void visit(AstPin* nodep) override { + void visit(AstPin* nodep) override { if (nodep->modVarp() && nodep->modVarp()->isWritable()) { // When the varref's were created, we didn't know the I/O state // Now that we do, and it's from a output, we know it's a lvalue @@ -72,19 +75,23 @@ private: iterateChildren(nodep); } } - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { VL_RESTORER(m_setRefLvalue); VL_RESTORER(m_setContinuously); { m_setRefLvalue = VAccess::WRITE; m_setContinuously = VN_IS(nodep, AssignW) || VN_IS(nodep, AssignAlias); + if (AstAssignW* assignwp = VN_CAST(nodep, AssignW)) { + if (assignwp->strengthSpecp()) m_setStrengthSpecified = true; + } iterateAndNextNull(nodep->lhsp()); m_setRefLvalue = VAccess::NOCHANGE; m_setContinuously = false; + m_setStrengthSpecified = false; iterateAndNextNull(nodep->rhsp()); } } - virtual void visit(AstRelease* nodep) override { + void visit(AstRelease* nodep) override { VL_RESTORER(m_setRefLvalue); VL_RESTORER(m_setContinuously); { @@ -93,7 +100,7 @@ private: iterateAndNextNull(nodep->lhsp()); } } - virtual void visit(AstCastDynamic* nodep) override { + void visit(AstCastDynamic* nodep) override { VL_RESTORER(m_setRefLvalue); { m_setRefLvalue = VAccess::NOCHANGE; @@ -102,7 +109,7 @@ private: iterateAndNextNull(nodep->top()); } } - virtual void visit(AstFOpen* nodep) override { + void visit(AstFOpen* nodep) override { VL_RESTORER(m_setRefLvalue); { m_setRefLvalue = VAccess::WRITE; @@ -112,7 +119,7 @@ private: iterateAndNextNull(nodep->modep()); } } - virtual void visit(AstFOpenMcd* nodep) override { + void visit(AstFOpenMcd* nodep) override { VL_RESTORER(m_setRefLvalue); { m_setRefLvalue = VAccess::WRITE; @@ -121,14 +128,14 @@ private: iterateAndNextNull(nodep->filenamep()); } } - virtual void visit(AstFClose* nodep) override { + void visit(AstFClose* nodep) override { VL_RESTORER(m_setRefLvalue); { m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->filep()); } } - virtual void visit(AstFError* nodep) override { + void visit(AstFError* nodep) override { VL_RESTORER(m_setRefLvalue); { m_setRefLvalue = VAccess::WRITE; @@ -136,21 +143,21 @@ private: iterateAndNextNull(nodep->strp()); } } - virtual void visit(AstFFlush* nodep) override { + void visit(AstFFlush* nodep) override { VL_RESTORER(m_setRefLvalue); { m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->filep()); } } - virtual void visit(AstFGetC* nodep) override { + void visit(AstFGetC* nodep) override { VL_RESTORER(m_setRefLvalue); { m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->filep()); } } - virtual void visit(AstFGetS* nodep) override { + void visit(AstFGetS* nodep) override { VL_RESTORER(m_setRefLvalue); { m_setRefLvalue = VAccess::WRITE; @@ -158,7 +165,7 @@ private: iterateAndNextNull(nodep->strgp()); } } - virtual void visit(AstFRead* nodep) override { + void visit(AstFRead* nodep) override { VL_RESTORER(m_setRefLvalue); { m_setRefLvalue = VAccess::WRITE; @@ -166,7 +173,7 @@ private: iterateAndNextNull(nodep->filep()); } } - virtual void visit(AstFScanF* nodep) override { + void visit(AstFScanF* nodep) override { VL_RESTORER(m_setRefLvalue); { m_setRefLvalue = VAccess::WRITE; @@ -174,33 +181,33 @@ private: iterateAndNextNull(nodep->exprsp()); } } - virtual void visit(AstFUngetC* nodep) override { + void visit(AstFUngetC* nodep) override { VL_RESTORER(m_setRefLvalue); { m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->filep()); } } - virtual void visit(AstSScanF* nodep) override { + void visit(AstSScanF* nodep) override { VL_RESTORER(m_setRefLvalue); { m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->exprsp()); } } - virtual void visit(AstSysIgnore* nodep) override { + void visit(AstSysIgnore* nodep) override { // Can't know if lvalue or not; presume so as stricter VL_RESTORER(m_setRefLvalue); iterateChildren(nodep); } - virtual void visit(AstRand* nodep) override { + void visit(AstRand* nodep) override { VL_RESTORER(m_setRefLvalue); { if (!nodep->urandom()) m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->seedp()); } } - virtual void visit(AstReadMem* nodep) override { + void visit(AstReadMem* nodep) override { VL_RESTORER(m_setRefLvalue); { m_setRefLvalue = VAccess::WRITE; @@ -211,14 +218,14 @@ private: iterateAndNextNull(nodep->msbp()); } } - virtual void visit(AstTestPlusArgs* nodep) override { + void visit(AstTestPlusArgs* nodep) override { VL_RESTORER(m_setRefLvalue); { m_setRefLvalue = VAccess::NOCHANGE; iterateAndNextNull(nodep->searchp()); } } - virtual void visit(AstValuePlusArgs* nodep) override { + void visit(AstValuePlusArgs* nodep) override { VL_RESTORER(m_setRefLvalue); { m_setRefLvalue = VAccess::NOCHANGE; @@ -227,7 +234,7 @@ private: iterateAndNextNull(nodep->outp()); } } - virtual void visit(AstSFormat* nodep) override { + void visit(AstSFormat* nodep) override { VL_RESTORER(m_setRefLvalue); { m_setRefLvalue = VAccess::WRITE; @@ -246,13 +253,13 @@ private: iterateAndNextNull(nodep->thsp()); } } - virtual void visit(AstPreAdd* nodep) override { prepost_visit(nodep); } - virtual void visit(AstPostAdd* nodep) override { prepost_visit(nodep); } - virtual void visit(AstPreSub* nodep) override { prepost_visit(nodep); } - virtual void visit(AstPostSub* nodep) override { prepost_visit(nodep); } + void visit(AstPreAdd* nodep) override { prepost_visit(nodep); } + void visit(AstPostAdd* nodep) override { prepost_visit(nodep); } + void visit(AstPreSub* nodep) override { prepost_visit(nodep); } + void visit(AstPostSub* nodep) override { prepost_visit(nodep); } // Nodes that change LValue state - virtual void visit(AstSel* nodep) override { + void visit(AstSel* nodep) override { VL_RESTORER(m_setRefLvalue); { iterateAndNextNull(nodep->lhsp()); @@ -262,7 +269,7 @@ private: iterateAndNextNull(nodep->thsp()); } } - virtual void visit(AstNodeSel* nodep) override { + void visit(AstNodeSel* nodep) override { VL_RESTORER(m_setRefLvalue); { // Only set lvalues on the from iterateAndNextNull(nodep->lhsp()); @@ -270,14 +277,14 @@ private: iterateAndNextNull(nodep->rhsp()); } } - virtual void visit(AstCellArrayRef* nodep) override { + void visit(AstCellArrayRef* nodep) override { VL_RESTORER(m_setRefLvalue); { // selp is not an lvalue m_setRefLvalue = VAccess::NOCHANGE; iterateAndNextNull(nodep->selp()); } } - virtual void visit(AstNodePreSel* nodep) override { + void visit(AstNodePreSel* nodep) override { VL_RESTORER(m_setRefLvalue); { // Only set lvalues on the from iterateAndNextNull(nodep->fromp()); @@ -286,12 +293,12 @@ private: iterateAndNextNull(nodep->thsp()); } } - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstNodeFTask* nodep) override { m_ftaskp = nodep; iterateChildren(nodep); m_ftaskp = nullptr; } - virtual void visit(AstNodeFTaskRef* nodep) override { + void visit(AstNodeFTaskRef* nodep) override { AstNode* pinp = nodep->pinsp(); const AstNodeFTask* const taskp = nodep->taskp(); // We'll deal with mismatching pins later @@ -313,7 +320,7 @@ private: } } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -321,7 +328,7 @@ public: : m_setRefLvalue{start} { iterate(nodep); } - virtual ~LinkLValueVisitor() override = default; + ~LinkLValueVisitor() override = default; }; //###################################################################### @@ -330,7 +337,7 @@ public: void V3LinkLValue::linkLValue(AstNetlist* nodep) { UINFO(4, __FUNCTION__ << ": " << endl); { LinkLValueVisitor{nodep, VAccess::NOCHANGE}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("linklvalue", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6); + V3Global::dumpCheckGlobalTree("linklvalue", 0, dumpTree() >= 6); } void V3LinkLValue::linkLValueSet(AstNode* nodep) { // Called by later link functions when it is known a node needs diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index b9ecca249..cdb9b19c8 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -31,6 +31,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Levelizing class functions @@ -76,9 +78,9 @@ void V3LinkLevel::modSortByLevel() { UINFO(9, "modSortByLevel() sorted\n"); // Comment required for gcc4.6.3 / bug666 for (AstNodeModule* nodep : mods) nodep->unlinkFrBack(); UASSERT_OBJ(!v3Global.rootp()->modulesp(), v3Global.rootp(), "Unlink didn't work"); - for (AstNodeModule* nodep : mods) v3Global.rootp()->addModulep(nodep); + for (AstNodeModule* nodep : mods) v3Global.rootp()->addModulesp(nodep); UINFO(9, "modSortByLevel() done\n"); // Comment required for gcc4.6.3 / bug666 - V3Global::dumpCheckGlobalTree("cells", false, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("cells", false, dumpTree() >= 3); } void V3LinkLevel::timescaling(const ModVec& mods) { @@ -94,7 +96,7 @@ void V3LinkLevel::timescaling(const ModVec& mods) { } } unit = v3Global.opt.timeComputeUnit(unit); // Apply override - if (unit.isNone()) unit = VTimescale(VTimescale::TS_DEFAULT); + if (unit.isNone()) unit = VTimescale{VTimescale::TS_DEFAULT}; v3Global.rootp()->timeunit(unit); bool dunitTimed = false; // $unit had a timeunit @@ -127,7 +129,7 @@ void V3LinkLevel::timescaling(const ModVec& mods) { if (v3Global.rootp()->timeprecision().isNone()) { v3Global.rootp()->timeprecisionMerge(v3Global.rootp()->fileline(), - VTimescale(VTimescale::TS_DEFAULT)); + VTimescale{VTimescale::TS_DEFAULT}); } // Classes under package have timescale propaged in V3LinkParse @@ -154,7 +156,7 @@ void V3LinkLevel::wrapTop(AstNetlist* rootp) { newmodp->modPublic(true); newmodp->protect(false); newmodp->timeunit(oldmodp->timeunit()); - rootp->addModulep(newmodp); + rootp->addModulesp(newmodp); // TODO the module creation above could be done after linkcells, but // the rest must be done after data type resolution @@ -170,11 +172,11 @@ void V3LinkLevel::wrapTop(AstNetlist* rootp) { // with module names/"v" modp->name(), modp->name(), nullptr, nullptr, nullptr); cellp->modp(modp); - newmodp->addStmtp(cellp); + newmodp->addStmtsp(cellp); } } - V3Global::dumpCheckGlobalTree("wraptop", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6); + V3Global::dumpCheckGlobalTree("wraptop", 0, dumpTree() >= 6); } void V3LinkLevel::wrapTopCell(AstNetlist* rootp) { @@ -213,7 +215,7 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) { (!v3Global.opt.l2Name().empty() ? v3Global.opt.l2Name() : oldmodp->name()), oldmodp->name(), nullptr, nullptr, nullptr); cellp->modp(oldmodp); - newmodp->addStmtp(cellp); + newmodp->addStmtsp(cellp); // Add pins for (AstNode* subnodep = oldmodp->stmtsp(); subnodep; subnodep = subnodep->nextp()) { @@ -229,7 +231,7 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) { AstVar* const varp = oldvarp->cloneTree(false); varp->name(name); varp->protect(false); - newmodp->addStmtp(varp); + newmodp->addStmtsp(varp); varp->sigPublic(true); // User needs to be able to get to it... if (oldvarp->isIO()) { oldvarp->primaryIO(false); diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 2acc01f3e..43ade69e9 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -32,6 +32,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Link state, as a visitor of each AstNode @@ -62,8 +64,6 @@ private: VLifetime m_lifetime = VLifetime::STATIC; // Propagating lifetime // METHODS - VL_DEBUG_FUNC; // Declare debug() - void cleanFileline(AstNode* nodep) { if (!nodep->user2SetOnce()) { // Process once // We make all filelines unique per AstNode. This allows us to @@ -73,7 +73,7 @@ private: // We could have verilog.l create a new one on every token, // but that's a lot more structures than only doing AST nodes. if (m_filelines.find(nodep->fileline()) != m_filelines.end()) { - nodep->fileline(new FileLine(nodep->fileline())); + nodep->fileline(new FileLine{nodep->fileline()}); } m_filelines.insert(nodep->fileline()); } @@ -122,7 +122,7 @@ private: } // VISITs - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstNodeFTask* nodep) override { if (!nodep->user1SetOnce()) { // Process only once. V3Config::applyFTask(m_modp, nodep); cleanFileline(nodep); @@ -139,7 +139,7 @@ private: } } } - virtual void visit(AstNodeFTaskRef* nodep) override { + void visit(AstNodeFTaskRef* nodep) override { if (!nodep->user1SetOnce()) { // Process only once. cleanFileline(nodep); UINFO(5, " " << nodep << endl); @@ -150,20 +150,20 @@ private: } } } - virtual void visit(AstNodeDType* nodep) override { visitIterateNodeDType(nodep); } - virtual void visit(AstEnumDType* nodep) override { + void visit(AstNodeDType* nodep) override { visitIterateNodeDType(nodep); } + void visit(AstEnumDType* nodep) override { if (nodep->name() == "") { nodep->name(nameFromTypedef(nodep)); // Might still remain "" } visitIterateNodeDType(nodep); } - virtual void visit(AstNodeUOrStructDType* nodep) override { + void visit(AstNodeUOrStructDType* nodep) override { if (nodep->name() == "") { nodep->name(nameFromTypedef(nodep)); // Might still remain "" } visitIterateNodeDType(nodep); } - virtual void visit(AstEnumItem* nodep) override { + void visit(AstEnumItem* nodep) override { // Expand ranges cleanFileline(nodep); iterateChildren(nodep); @@ -177,28 +177,24 @@ private: const int right = nodep->rangep()->rightConst(); const int increment = (left > right) ? -1 : 1; int offset_from_init = 0; - AstNode* addp = nullptr; + AstEnumItem* addp = nullptr; + FileLine* const flp = nodep->fileline(); for (int i = left; i != (right + increment); i += increment, offset_from_init++) { const string name = nodep->name() + cvtToStr(i); AstNode* valuep = nullptr; if (nodep->valuep()) { - valuep = new AstAdd( - nodep->fileline(), nodep->valuep()->cloneTree(true), - new AstConst(nodep->fileline(), AstConst::Unsized32(), offset_from_init)); - } - AstNode* const newp = new AstEnumItem(nodep->fileline(), name, nullptr, valuep); - if (addp) { - addp = addp->addNextNull(newp); - } else { - addp = newp; + valuep + = new AstAdd(flp, nodep->valuep()->cloneTree(true), + new AstConst(flp, AstConst::Unsized32(), offset_from_init)); } + addp = AstNode::addNext(addp, new AstEnumItem{flp, name, nullptr, valuep}); } nodep->replaceWith(addp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } } - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { cleanFileline(nodep); if (nodep->lifetime().isNone()) { if (m_ftaskp) { @@ -296,7 +292,7 @@ private: } } - virtual void visit(AstAttrOf* nodep) override { + void visit(AstAttrOf* nodep) override { cleanFileline(nodep); iterateChildren(nodep); if (nodep->attrType() == VAttrType::DT_PUBLIC) { @@ -365,23 +361,23 @@ private: } } - virtual void visit(AstAlwaysPublic* nodep) override { + void visit(AstAlwaysPublic* nodep) override { // AlwaysPublic was attached under a var, but it's a statement that should be // at the same level as the var cleanFileline(nodep); iterateChildren(nodep); if (m_varp) { nodep->unlinkFrBack(); - m_varp->addNext(nodep); + AstNode::addNext(m_varp, nodep); // lvalue is true, because we know we have a verilator public_flat_rw // but someday we may be more general const bool lvalue = m_varp->isSigUserRWPublic(); - nodep->addStmtp( + nodep->addStmtsp( new AstVarRef(nodep->fileline(), m_varp, lvalue ? VAccess::WRITE : VAccess::READ)); } } - virtual void visit(AstDefImplicitDType* nodep) override { + void visit(AstDefImplicitDType* nodep) override { cleanFileline(nodep); UINFO(8, " DEFIMPLICIT " << nodep << endl); // Must remember what names we've already created, and combine duplicates @@ -422,7 +418,7 @@ private: VL_DO_DANGLING(nodep->deleteTree(), nodep); } - virtual void visit(AstForeach* nodep) override { + void visit(AstForeach* nodep) override { // FOREACH(array, loopvars, body) UINFO(9, "FOREACH " << nodep << endl); // Separate iteration vars from base from variable @@ -457,7 +453,7 @@ private: iterateChildren(nodep); } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { V3Config::applyModule(nodep); VL_RESTORER(m_modp); @@ -490,16 +486,16 @@ private: iterateChildren(nodep); } } - virtual void visit(AstNodeProcedure* nodep) override { visitIterateNoValueMod(nodep); } - virtual void visit(AstAlways* nodep) override { + void visit(AstNodeProcedure* nodep) override { visitIterateNoValueMod(nodep); } + void visit(AstAlways* nodep) override { VL_RESTORER(m_inAlways); m_inAlways = true; visitIterateNoValueMod(nodep); } - virtual void visit(AstCover* nodep) override { visitIterateNoValueMod(nodep); } - virtual void visit(AstRestrict* nodep) override { visitIterateNoValueMod(nodep); } + void visit(AstCover* nodep) override { visitIterateNoValueMod(nodep); } + void visit(AstRestrict* nodep) override { visitIterateNoValueMod(nodep); } - virtual void visit(AstBegin* nodep) override { + void visit(AstBegin* nodep) override { V3Config::applyCoverageBlock(m_modp, nodep); cleanFileline(nodep); const AstNode* const backp = nodep->backp(); @@ -525,7 +521,7 @@ private: iterateChildren(nodep); } } - virtual void visit(AstGenCase* nodep) override { + void visit(AstGenCase* nodep) override { ++m_genblkNum; cleanFileline(nodep); { @@ -536,7 +532,7 @@ private: iterateChildren(nodep); } } - virtual void visit(AstGenIf* nodep) override { + void visit(AstGenIf* nodep) override { cleanFileline(nodep); const bool nestedIf = (VN_IS(nodep->backp(), Begin) && nestedIfBegin(VN_CAST(nodep->backp(), Begin))); @@ -551,39 +547,39 @@ private: iterateChildren(nodep); } } - virtual void visit(AstCase* nodep) override { + void visit(AstCase* nodep) override { V3Config::applyCase(nodep); cleanFileline(nodep); iterateChildren(nodep); } - virtual void visit(AstPrintTimeScale* nodep) override { + void visit(AstPrintTimeScale* nodep) override { // Inlining may change hierarchy, so just save timescale where needed cleanFileline(nodep); iterateChildren(nodep); nodep->name(m_modp->name()); nodep->timeunit(m_modp->timeunit()); } - virtual void visit(AstSFormatF* nodep) override { + void visit(AstSFormatF* nodep) override { cleanFileline(nodep); iterateChildren(nodep); nodep->timeunit(m_modp->timeunit()); } - virtual void visit(AstTime* nodep) override { + void visit(AstTime* nodep) override { cleanFileline(nodep); iterateChildren(nodep); nodep->timeunit(m_modp->timeunit()); } - virtual void visit(AstTimeD* nodep) override { + void visit(AstTimeD* nodep) override { cleanFileline(nodep); iterateChildren(nodep); nodep->timeunit(m_modp->timeunit()); } - virtual void visit(AstTimeImport* nodep) override { + void visit(AstTimeImport* nodep) override { cleanFileline(nodep); iterateChildren(nodep); nodep->timeunit(m_modp->timeunit()); } - virtual void visit(AstEventControl* nodep) override { + void visit(AstEventControl* nodep) override { cleanFileline(nodep); iterateChildren(nodep); AstAlways* const alwaysp = VN_CAST(nodep->backp(), Always); @@ -600,12 +596,12 @@ private: sensesp->unlinkFrBackWithNext(); alwaysp->sensesp(sensesp); } - if (nodep->stmtsp()) alwaysp->addStmtp(nodep->stmtsp()->unlinkFrBackWithNext()); + if (nodep->stmtsp()) alwaysp->addStmtsp(nodep->stmtsp()->unlinkFrBackWithNext()); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } } - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { // Default: Just iterate cleanFileline(nodep); iterateChildren(nodep); @@ -614,7 +610,7 @@ private: public: // CONSTRUCTORS explicit LinkParseVisitor(AstNetlist* rootp) { iterate(rootp); } - virtual ~LinkParseVisitor() override = default; + ~LinkParseVisitor() override = default; }; //###################################################################### @@ -623,5 +619,5 @@ public: void V3LinkParse::linkParse(AstNetlist* rootp) { UINFO(4, __FUNCTION__ << ": " << endl); { LinkParseVisitor{rootp}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("linkparse", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6); + V3Global::dumpCheckGlobalTree("linkparse", 0, dumpTree() >= 6); } diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index f1b859b51..9e314992a 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -36,6 +36,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Link state, as a visitor of each AstNode @@ -55,14 +57,11 @@ private: int m_senitemCvtNum = 0; // Temporary signal counter bool m_underGenerate = false; // Under GenFor/GenIf - // METHODS - VL_DEBUG_FUNC; // Declare debug() - // VISITs // TODO: Most of these visitors are here for historical reasons. // TODO: ExpectDecriptor can move to data type resolution, and the rest // TODO: could move to V3LinkParse to get them out of the way of elaboration - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { // Module: Create sim table for entire module and iterate UINFO(8, "MODULE " << nodep << endl); if (nodep->dead()) return; @@ -74,28 +73,28 @@ private: iterateChildren(nodep); } } - virtual void visit(AstClass* nodep) override { + void visit(AstClass* nodep) override { VL_RESTORER(m_classp); { m_classp = nodep; iterateChildren(nodep); } } - virtual void visit(AstInitialAutomatic* nodep) override { + void visit(AstInitialAutomatic* nodep) override { iterateChildren(nodep); // Initial assignments under function/tasks can just be simple // assignments without the initial if (m_ftaskp) { - VL_DO_DANGLING(nodep->replaceWith(nodep->bodysp()->unlinkFrBackWithNext()), nodep); + VL_DO_DANGLING(nodep->replaceWith(nodep->stmtsp()->unlinkFrBackWithNext()), nodep); } } - virtual void visit(AstNodeCoverOrAssert* nodep) override { + void visit(AstNodeCoverOrAssert* nodep) override { if (m_assertp) nodep->v3error("Assert not allowed under another assert"); m_assertp = nodep; iterateChildren(nodep); m_assertp = nullptr; } - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { iterateChildren(nodep); if (m_classp && !nodep->isParam()) nodep->varType(VVarType::MEMBER); if (m_ftaskp) nodep->funcLocal(true); @@ -105,13 +104,13 @@ private: } } - virtual void visit(AstNodeVarRef* nodep) override { + void visit(AstNodeVarRef* nodep) override { // VarRef: Resolve its reference if (nodep->varp()) nodep->varp()->usedParam(true); iterateChildren(nodep); } - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstNodeFTask* nodep) override { // NodeTask: Remember its name for later resolution if (m_underGenerate) nodep->underGenerate(true); // Remember the existing symbol table scope @@ -139,14 +138,14 @@ private: m_ftaskp = nullptr; if (nodep->dpiExport()) nodep->scopeNamep(new AstScopeName{nodep->fileline(), false}); } - virtual void visit(AstNodeFTaskRef* nodep) override { + void visit(AstNodeFTaskRef* nodep) override { iterateChildren(nodep); if (nodep->taskp() && (nodep->taskp()->dpiContext() || nodep->taskp()->dpiExport())) { nodep->scopeNamep(new AstScopeName{nodep->fileline(), false}); } } - virtual void visit(AstSenItem* nodep) override { + void visit(AstSenItem* nodep) override { // Remove bit selects, and bark if it's not a simple variable iterateChildren(nodep); if (nodep->isClocked()) { @@ -214,7 +213,7 @@ private: } } - virtual void visit(AstNodePreSel* nodep) override { + void visit(AstNodePreSel* nodep) override { if (!nodep->attrp()) { iterateChildren(nodep); // Constification may change the fromp() to a constant, which will lose the @@ -249,7 +248,7 @@ private: } } - virtual void visit(AstCaseItem* nodep) override { + void visit(AstCaseItem* nodep) override { // Move default caseItems to the bottom of the list // That saves us from having to search each case list twice, for non-defaults and defaults iterateChildren(nodep); @@ -261,7 +260,7 @@ private: } } - virtual void visit(AstPragma* nodep) override { + void visit(AstPragma* nodep) override { if (nodep->pragType() == VPragmaType::HIER_BLOCK) { UASSERT_OBJ(m_modp, nodep, "HIER_BLOCK not under a module"); // If this is hierarchical mode which is to lib-create, @@ -411,39 +410,39 @@ private: if (filep && filep->varp()) filep->varp()->attrFileDescr(true); } - virtual void visit(AstFOpen* nodep) override { + void visit(AstFOpen* nodep) override { iterateChildren(nodep); expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef)); } - virtual void visit(AstFOpenMcd* nodep) override { + void visit(AstFOpenMcd* nodep) override { iterateChildren(nodep); expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef)); } - virtual void visit(AstFClose* nodep) override { + void visit(AstFClose* nodep) override { iterateChildren(nodep); expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef)); } - virtual void visit(AstFError* nodep) override { + void visit(AstFError* nodep) override { iterateChildren(nodep); expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef)); } - virtual void visit(AstFEof* nodep) override { + void visit(AstFEof* nodep) override { iterateChildren(nodep); expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef)); } - virtual void visit(AstFRead* nodep) override { + void visit(AstFRead* nodep) override { iterateChildren(nodep); expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef)); } - virtual void visit(AstFScanF* nodep) override { + void visit(AstFScanF* nodep) override { iterateChildren(nodep); expectFormat(nodep, nodep->text(), nodep->exprsp(), true); } - virtual void visit(AstSScanF* nodep) override { + void visit(AstSScanF* nodep) override { iterateChildren(nodep); expectFormat(nodep, nodep->text(), nodep->exprsp(), true); } - virtual void visit(AstSFormatF* nodep) override { + void visit(AstSFormatF* nodep) override { iterateChildren(nodep); // Cleanup old-school displays without format arguments if (!nodep->hasFormat()) { @@ -466,7 +465,7 @@ private: } } - virtual void visit(AstUdpTable* nodep) override { + void visit(AstUdpTable* nodep) override { UINFO(5, "UDPTABLE " << nodep << endl); if (!v3Global.opt.bboxUnsup()) { // We don't warn until V3Inst, so that UDPs that are in libraries and @@ -483,7 +482,7 @@ private: } varoutp = varp; // Tie off - m_modp->addStmtp( + m_modp->addStmtsp( new AstAssignW(varp->fileline(), new AstVarRef(varp->fileline(), varp, VAccess::WRITE), new AstConst(varp->fileline(), AstConst::BitFalse()))); @@ -497,49 +496,49 @@ private: } } - virtual void visit(AstScCtor* nodep) override { + void visit(AstScCtor* nodep) override { // Constructor info means the module must remain public m_modp->modPublic(true); iterateChildren(nodep); } - virtual void visit(AstScDtor* nodep) override { + void visit(AstScDtor* nodep) override { // Destructor info means the module must remain public m_modp->modPublic(true); iterateChildren(nodep); } - virtual void visit(AstScInt* nodep) override { + void visit(AstScInt* nodep) override { // Special class info means the module must remain public m_modp->modPublic(true); iterateChildren(nodep); } - virtual void visit(AstIfaceRefDType* nodep) override { + void visit(AstIfaceRefDType* nodep) override { // LinkDot checked modports, now remove references to them // Keeping them later caused problems with InstDeArray, // as it needed to make new modport arrays and such nodep->modportp(nullptr); iterateChildren(nodep); } - // virtual void visit(AstModport* nodep) override { ... } + // void visit(AstModport* nodep) override { ... } // We keep Modport's themselves around for XML dump purposes - virtual void visit(AstGenFor* nodep) override { + void visit(AstGenFor* nodep) override { VL_RESTORER(m_underGenerate); m_underGenerate = true; iterateChildren(nodep); } - virtual void visit(AstGenIf* nodep) override { + void visit(AstGenIf* nodep) override { VL_RESTORER(m_underGenerate); m_underGenerate = true; iterateChildren(nodep); } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit LinkResolveVisitor(AstNetlist* rootp) { iterate(rootp); } - virtual ~LinkResolveVisitor() override = default; + ~LinkResolveVisitor() override = default; }; //###################################################################### @@ -552,33 +551,30 @@ private: // STATE AstNodeModule* m_modp = nullptr; // Current module - // METHODS - VL_DEBUG_FUNC; // Declare debug() - // VISITs - virtual void visit(AstNetlist* nodep) override { + void visit(AstNetlist* nodep) override { // Iterate modules backwards, in bottom-up order. iterateChildrenBackwards(nodep); } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { VL_RESTORER(m_modp); { m_modp = nodep; iterateChildren(nodep); } } - virtual void visit(AstCell* nodep) override { + void visit(AstCell* nodep) override { // Parent module inherits child's publicity if (nodep->modp()->modPublic()) m_modp->modPublic(true); //** No iteration for speed } - virtual void visit(AstNodeMath*) override {} // Accelerate - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit LinkBotupVisitor(AstNetlist* rootp) { iterate(rootp); } - virtual ~LinkBotupVisitor() override = default; + ~LinkBotupVisitor() override = default; }; //###################################################################### @@ -590,5 +586,5 @@ void V3LinkResolve::linkResolve(AstNetlist* rootp) { const LinkResolveVisitor visitor{rootp}; LinkBotupVisitor{rootp}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("linkresolve", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6); + V3Global::dumpCheckGlobalTree("linkresolve", 0, dumpTree() >= 6); } diff --git a/src/V3Localize.cpp b/src/V3Localize.cpp index 27d652110..0d5977dcc 100644 --- a/src/V3Localize.cpp +++ b/src/V3Localize.cpp @@ -34,6 +34,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // LocalizeVisitor @@ -62,8 +64,6 @@ private: std::vector m_varScopeps; // List of variables to consider for localization // METHODS - VL_DEBUG_FUNC; // Declare debug() - bool isOptimizable(AstVarScope* nodep) { return !nodep->user1() || // Not marked as not optimizable, or ... (nodep->varp()->varType() == VVarType::BLOCKTEMP @@ -123,12 +123,12 @@ private: } // VISITORS - virtual void visit(AstNetlist* nodep) override { + void visit(AstNetlist* nodep) override { iterateChildrenConst(nodep); moveVarScopes(); } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { UINFO(4, " CFUNC " << nodep << endl); VL_RESTORER(m_cfuncp); VL_RESTORER(m_nodeDepth); @@ -140,12 +140,12 @@ private: } } - virtual void visit(AstCCall* nodep) override { + void visit(AstCCall* nodep) override { m_cfuncp->user1(true); // Mark caller as not a leaf function iterateChildrenConst(nodep); } - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { // Analyze RHS first so "a = a + 1" is detected as a read before write iterate(nodep->rhsp()); // For now we only consider an assignment that is directly under the function, (in @@ -163,7 +163,7 @@ private: iterate(nodep->lhsp()); } - virtual void visit(AstVarScope* nodep) override { + void visit(AstVarScope* nodep) override { if (!nodep->varp()->isPrimaryIO() // Not an IO the user wants to interact with && !nodep->varp()->isSigPublic() // Not something the user wants to interact with && !nodep->varp()->isFuncLocal() // Not already a function local (e.g.: argument) @@ -177,7 +177,7 @@ private: // No iterate; Don't want varrefs under it (e.g.: in child dtype?) } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { UASSERT_OBJ(m_cfuncp, nodep, "AstVarRef not under function"); AstVarScope* const varScopep = nodep->varScopep(); @@ -201,7 +201,7 @@ private: // No iterate; Don't want varrefs under it (e.g.: in child dtype?) } - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { ++m_nodeDepth; iterateChildrenConst(nodep); --m_nodeDepth; @@ -210,7 +210,7 @@ private: public: // CONSTRUCTORS explicit LocalizeVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~LocalizeVisitor() override { + ~LocalizeVisitor() override { V3Stats::addStat("Optimizations, Vars localized", m_statLocVars); } }; @@ -221,5 +221,5 @@ public: void V3Localize::localizeAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { LocalizeVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("localize", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6); + V3Global::dumpCheckGlobalTree("localize", 0, dumpTree() >= 6); } diff --git a/src/V3MergeCond.cpp b/src/V3MergeCond.cpp index bb3389861..6103c62b1 100644 --- a/src/V3MergeCond.cpp +++ b/src/V3MergeCond.cpp @@ -87,6 +87,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + namespace { //###################################################################### @@ -455,7 +457,6 @@ private: StmtPropertiesAllocator* m_stmtPropertiesp = nullptr; // METHODS - VL_DEBUG_FUNC; // Declare debug() // Function that processes a whole sub-tree void process(AstNode* nodep) { @@ -565,7 +566,7 @@ private: return false; } if (const AstNodeCond* const condp = VN_CAST(nodep, NodeCond)) { - return yieldsOneOrZero(condp->expr1p()) && yieldsOneOrZero(condp->expr2p()); + return yieldsOneOrZero(condp->thenp()) && yieldsOneOrZero(condp->elsep()); } if (const AstCCast* const castp = VN_CAST(nodep, CCast)) { // Cast never sign extends @@ -593,7 +594,7 @@ private: return new AstConst{rhsp->fileline(), AstConst::BitTrue{}, condTrue}; } else if (const AstNodeCond* const condp = extractCondFromRhs(rhsp)) { AstNode* const resp - = condTrue ? condp->expr1p()->unlinkFrBack() : condp->expr2p()->unlinkFrBack(); + = condTrue ? condp->thenp()->unlinkFrBack() : condp->elsep()->unlinkFrBack(); if (condp == rhsp) return resp; if (const AstAnd* const andp = VN_CAST(rhsp, And)) { UASSERT_OBJ(andp->rhsp() == condp, rhsp, "Should not try to fold this"); @@ -676,7 +677,7 @@ private: // Construct the new RHSs and add to branches thenp->rhsp(foldAndUnlink(rhsp, true)); elsep->rhsp(foldAndUnlink(rhsp, false)); - resultp->addIfsp(thenp); + resultp->addThensp(thenp); resultp->addElsesp(elsep); // Cleanup VL_DO_DANGLING(rhsp->deleteTree(), rhsp); @@ -684,8 +685,8 @@ private: AstNodeIf* const ifp = VN_AS(currp, NodeIf); UASSERT_OBJ(ifp, currp, "Must be AstNodeIf"); // Move branch contents under new if - if (AstNode* const listp = ifp->ifsp()) { - resultp->addIfsp(listp->unlinkFrBackWithNext()); + if (AstNode* const listp = ifp->thensp()) { + resultp->addThensp(listp->unlinkFrBackWithNext()); } if (AstNode* const listp = ifp->elsesp()) { resultp->addElsesp(listp->unlinkFrBackWithNext()); @@ -695,7 +696,7 @@ private: } } while (nextp); // Merge the branches of the resulting AstIf after re-analysis - if (resultp->ifsp()) m_workQueuep->push(resultp->ifsp()); + if (resultp->thensp()) m_workQueuep->push(resultp->thensp()); if (resultp->elsesp()) m_workQueuep->push(resultp->elsesp()); } else if (AstNodeIf* const ifp = VN_CAST(m_mgFirstp, NodeIf)) { // There was nothing to merge this AstNodeIf with, so try to merge its branches. @@ -711,7 +712,7 @@ private: AstNode::user2ClearTree(); // Merge recursively within the branches of an un-merged AstNodeIF if (recursivep) { - iterateAndNextNull(recursivep->ifsp()); + iterateAndNextNull(recursivep->thensp()); iterateAndNextNull(recursivep->elsesp()); // Close a pending merge to ensure merge state is // reset as expected at the end of this function @@ -823,7 +824,7 @@ private: } // VISITORS - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { if (AstNode* const condp = (*m_stmtPropertiesp)(nodep).m_condp) { // Check if mergeable if (!checkOrMakeMergeable(nodep)) return; @@ -836,11 +837,11 @@ private: } } - virtual void visit(AstNodeIf* nodep) override { + void visit(AstNodeIf* nodep) override { // Check if mergeable if (!checkOrMakeMergeable(nodep)) { // If not mergeable, try to merge the branches - iterateAndNextNull(nodep->ifsp()); + iterateAndNextNull(nodep->thensp()); iterateAndNextNull(nodep->elsesp()); return; } @@ -850,25 +851,25 @@ private: addToList(nodep, nodep->condp()); } - virtual void visit(AstNodeStmt* nodep) override { + void visit(AstNodeStmt* nodep) override { if (m_mgFirstp && addIfHelpfulElseEndMerge(nodep)) return; iterateChildren(nodep); } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { // Merge function body if (nodep->stmtsp()) process(nodep->stmtsp()); } // For speed, only iterate what is necessary. - virtual void visit(AstNetlist* nodep) override { iterateAndNextNull(nodep->modulesp()); } - virtual void visit(AstNodeModule* nodep) override { iterateAndNextNull(nodep->stmtsp()); } - virtual void visit(AstNode* nodep) override {} + void visit(AstNetlist* nodep) override { iterateAndNextNull(nodep->modulesp()); } + void visit(AstNodeModule* nodep) override { iterateAndNextNull(nodep->stmtsp()); } + void visit(AstNode* nodep) override {} public: // CONSTRUCTORS explicit MergeCondVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~MergeCondVisitor() override { + ~MergeCondVisitor() override { V3Stats::addStat("Optimizations, MergeCond merges", m_statMerges); V3Stats::addStat("Optimizations, MergeCond merged items", m_statMergedItems); V3Stats::addStat("Optimizations, MergeCond longest merge", m_statLongestList); @@ -883,5 +884,5 @@ public: void V3MergeCond::mergeAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { MergeCondVisitor{nodep}; } - V3Global::dumpCheckGlobalTree("merge_cond", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6); + V3Global::dumpCheckGlobalTree("merge_cond", 0, dumpTree() >= 6); } diff --git a/src/V3Name.cpp b/src/V3Name.cpp index 9c3b422c8..8cb27838d 100644 --- a/src/V3Name.cpp +++ b/src/V3Name.cpp @@ -28,6 +28,8 @@ #include "V3Global.h" #include "V3LanguageWords.h" +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Name state, as a visitor of each AstNode @@ -44,8 +46,6 @@ private: const AstNodeModule* m_modp = nullptr; // METHODS - VL_DEBUG_FUNC; // Declare debug() - void rename(AstNode* nodep, bool addPvt) { if (!nodep->user1()) { // Not already done if (addPvt) { @@ -68,7 +68,7 @@ private: } // VISITORS - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { VL_RESTORER(m_modp); { m_modp = nodep; @@ -76,44 +76,44 @@ private: } } // Add __PVT__ to names of local signals - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { // Don't iterate... Don't need temps for RANGES under the Var. rename(nodep, ((!m_modp || !m_modp->isTop()) && !nodep->isSigPublic() && !nodep->isFuncLocal() // Isn't exposed, and would mess up dpi import wrappers && !nodep->isTemp())); // Don't bother to rename internal signals } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { if (!nodep->user1()) { iterateChildren(nodep); rename(nodep, false); } } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { if (nodep->varp()) { iterate(nodep->varp()); nodep->name(nodep->varp()->name()); } } - virtual void visit(AstCell* nodep) override { + void visit(AstCell* nodep) override { if (!nodep->user1()) { rename(nodep, (!nodep->modp()->modPublic() && !VN_IS(nodep->modp(), ClassPackage))); iterateChildren(nodep); } } - virtual void visit(AstMemberDType* nodep) override { + void visit(AstMemberDType* nodep) override { if (!nodep->user1()) { rename(nodep, false); iterateChildren(nodep); } } - virtual void visit(AstMemberSel* nodep) override { + void visit(AstMemberSel* nodep) override { if (!nodep->user1()) { rename(nodep, false); iterateChildren(nodep); } } - virtual void visit(AstScope* nodep) override { + void visit(AstScope* nodep) override { if (!nodep->user1SetOnce()) { if (nodep->aboveScopep()) iterate(nodep->aboveScopep()); if (nodep->aboveCellp()) iterate(nodep->aboveCellp()); @@ -130,12 +130,12 @@ private: } //-------------------- - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit NameVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~NameVisitor() override = default; + ~NameVisitor() override = default; }; //###################################################################### @@ -144,5 +144,5 @@ public: void V3Name::nameAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { NameVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("name", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6); + V3Global::dumpCheckGlobalTree("name", 0, dumpTree() >= 6); } diff --git a/src/V3Number.cpp b/src/V3Number.cpp index d7473cd29..3dcfc88e2 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -27,6 +27,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + constexpr int MAX_SPRINTF_DOUBLE_SIZE = 1100; // Maximum characters with a sprintf %e/%f/%g (really 1079) @@ -44,7 +46,7 @@ constexpr int MAX_SPRINTF_DOUBLE_SIZE "Number operation called with same source and dest") #define NUM_ASSERT_LOGIC_ARGS1(arg1) \ - UASSERT((!(arg1).isDouble() && !(arg1).isString()), \ + UASSERT(((arg1).dataType() == V3NumberData::V3NumberDataType::LOGIC), \ "Number operation called with non-logic (double or string) argument: '" << (arg1) \ << '"') #define NUM_ASSERT_LOGIC_ARGS2(arg1, arg2) \ @@ -79,8 +81,10 @@ void V3Number::v3errorEnd(std::ostringstream& str) const { nsstr << str.str(); if (m_nodep) { m_nodep->v3errorEnd(nsstr); - } else { + } else if (m_fileline) { m_fileline->v3errorEnd(nsstr); + } else { + V3Error::v3errorEnd(nsstr); } } @@ -96,13 +100,11 @@ void V3Number::v3errorEndFatal(std::ostringstream& str) const { V3Number::V3Number(VerilogStringLiteral, AstNode* nodep, const string& str) { // Create a number using a verilog string as the value, thus 8 bits per character. - // cppcheck bug - doesn't see init() resets these - // cppcheck: Member variable 'm_sized/m_width' is not initialized in the constructor - init(nodep, str.length() * 8); - m_fromString = true; + init(nodep, std::max(str.length() * 8, 1)); + m_data.m_fromString = true; for (unsigned pos = 0; pos < str.length(); ++pos) { const int topos = str.length() - 1 - pos; - ValueAndX& v = m_value[topos / 4]; + ValueAndX& v = m_data.num()[topos / 4]; for (int bit = 0; bit < 8; ++bit) { if (str[pos] & (1UL << bit)) { v.m_value |= (1UL << (bit + (topos % 4) * 8)); } } @@ -112,7 +114,7 @@ V3Number::V3Number(VerilogStringLiteral, AstNode* nodep, const string& str) { V3Number::V3Number(AstNode* nodep, const AstNodeDType* nodedtypep) { if (nodedtypep->isString()) { - init(nodep, 0); + init(nodep); setString(""); } else if (nodedtypep->isDouble()) { init(nodep, 64); @@ -124,6 +126,7 @@ V3Number::V3Number(AstNode* nodep, const AstNodeDType* nodedtypep) { void V3Number::V3NumberCreate(AstNode* nodep, const char* sourcep, FileLine* fl) { init(nodep, 0); + m_data.setLogic(); m_fileline = fl; const char* value_startp = sourcep; for (const char* cp = sourcep; *cp; cp++) { @@ -156,14 +159,15 @@ void V3Number::V3NumberCreate(AstNode* nodep, const char* sourcep, FileLine* fl) } value_startp = cp; - if (atoi(widthn.c_str())) { - if (atoi(widthn.c_str()) < 0 || atoi(widthn.c_str()) > v3Global.opt.maxNumWidth()) { + if (std::atoi(widthn.c_str())) { + if (std::atoi(widthn.c_str()) < 0 + || std::atoi(widthn.c_str()) > v3Global.opt.maxNumWidth()) { // atoi might convert large number to negative, so can't tell which v3error("Unsupported: Width of number exceeds implementation limit: " << sourcep << " (IEEE 1800-2017 6.9.1)"); width(v3Global.opt.maxNumWidth(), true); } else { - width(atoi(widthn.c_str()), true); + width(std::atoi(widthn.c_str()), true); } } } else { @@ -171,35 +175,35 @@ void V3Number::V3NumberCreate(AstNode* nodep, const char* sourcep, FileLine* fl) base = 'd'; } - for (int i = 0; i < words(); ++i) m_value[i] = {0, 0}; + for (int i = 0; i < words(); ++i) m_data.num()[i] = {0, 0}; // Special SystemVerilog unsized constructs if (base == '0') { + width(1, false); // So we extend it setBit(0, 0); - width(1, false); // So we extend it - m_autoExtend = true; + m_data.m_autoExtend = true; } else if (base == '1') { + width(1, false); // So we extend it setBit(0, 1); - width(1, false); // So we extend it - m_autoExtend = true; + m_data.m_autoExtend = true; } else if (tolower(base) == 'z') { + width(1, false); // So we extend it setBit(0, 'z'); - width(1, false); // So we extend it - m_autoExtend = true; + m_data.m_autoExtend = true; } else if (tolower(base) == 'x') { - setBit(0, 'x'); width(1, false); // So we extend it - m_autoExtend = true; + setBit(0, 'x'); + m_data.m_autoExtend = true; } // Otherwise... - else if (!m_sized) { + else if (!sized()) { width(32, false); // Says IEEE 1800-2012 5.7.1 if (unbased) isSigned(true); // Also says the spec. } // Ignore leading blanks while (*value_startp == '_' || isspace(*value_startp)) value_startp++; - if (!*value_startp && !m_autoExtend) { + if (!*value_startp && !m_data.m_autoExtend) { v3error("Number is missing value digits: " << sourcep); } @@ -228,7 +232,7 @@ void V3Number::V3NumberCreate(AstNode* nodep, const char* sourcep, FileLine* fl) if (olen <= 7) { // 10000000 fits in 32 bits, so ok // Constants are common, so for speed avoid wide math until we need it val = val * 10 + (*cp - '0'); - m_value[0].m_value = val; + m_data.num()[0].m_value = val; } else { // Wide; all previous digits are already in m_value[0] // this = (this * 10)/*product*/ + (*cp-'0')/*addend*/ // Assumed rare; lots of optimizations are possible here @@ -236,12 +240,12 @@ void V3Number::V3NumberCreate(AstNode* nodep, const char* sourcep, FileLine* fl) const V3Number ten(this, width() + 4, 10); const V3Number addend(this, width(), (*cp - '0')); product.opMul(*this, ten); - this->opAdd(product, addend); + opAdd(product, addend); if (product.bitsValue(width(), 4)) { // Overflowed static int warned = 0; v3error("Too many digits for " << width() << " bit number: " << sourcep << '\n' - << ((!m_sized && !warned++) ? ( + << ((!sized() && !warned++) ? ( V3Error::warnMore() + "... As that number was unsized" + " ('d...) it is limited to 32 bits (IEEE 1800-2017 " "5.7.1)\n" @@ -278,7 +282,8 @@ void V3Number::V3NumberCreate(AstNode* nodep, const char* sourcep, FileLine* fl) } } else { // Convert bin/octal number to hex - for (const char* cp = value_startp + strlen(value_startp) - 1; cp >= value_startp; cp--) { + for (const char* cp = value_startp + std::strlen(value_startp) - 1; cp >= value_startp; + cp--) { if (*cp != '_' && *cp != '0' && obit >= width()) { v3error("Too many digits for " << width() << " bit number: " << sourcep); break; @@ -385,72 +390,72 @@ int V3Number::log2b(uint32_t num) { // Setters V3Number& V3Number::setZero() { - for (int i = 0; i < words(); i++) m_value[i] = {0, 0}; + for (int i = 0; i < words(); i++) m_data.num()[i] = {0, 0}; return *this; } V3Number& V3Number::setQuad(uint64_t value) { - for (int i = 0; i < words(); i++) m_value[i] = {0, 0}; - m_value[0].m_value = value & 0xffffffffULL; - if (width() > 32) m_value[1].m_value = (value >> 32ULL) & 0xffffffffULL; + for (int i = 0; i < words(); i++) m_data.num()[i] = {0, 0}; + m_data.num()[0].m_value = value & 0xffffffffULL; + if (width() > 32) m_data.num()[1].m_value = (value >> 32ULL) & 0xffffffffULL; opCleanThis(); return *this; } V3Number& V3Number::setLong(uint32_t value) { - for (int i = 0; i < words(); i++) m_value[i] = {0, 0}; - m_value[0].m_value = value; + for (int i = 0; i < words(); i++) m_data.num()[i] = {0, 0}; + m_data.num()[0].m_value = value; opCleanThis(); return *this; } V3Number& V3Number::setLongS(int32_t value) { - for (int i = 0; i < words(); i++) m_value[i] = {0, 0}; + for (int i = 0; i < words(); i++) m_data.num()[i] = {0, 0}; union { uint32_t u; int32_t s; } u; u.s = value; if (u.s) {} - m_value[0].m_value = u.u; + m_data.num()[0].m_value = u.u; opCleanThis(); return *this; } V3Number& V3Number::setDouble(double value) { if (VL_UNCOVERABLE(width() != 64)) v3fatalSrc("Real operation on wrong sized number"); - m_double = true; + m_data.setDouble(); union { double d; uint32_t u[2]; } u; u.d = value; if (u.d != 0.0) {} - for (int i = 2; i < words(); i++) m_value[i] = {0, 0}; - m_value[0].m_value = u.u[0]; - m_value[1].m_value = u.u[1]; + for (int i = 2; i < words(); i++) m_data.num()[i] = {0, 0}; + m_data.num()[0].m_value = u.u[0]; + m_data.num()[1].m_value = u.u[1]; return *this; } V3Number& V3Number::setSingleBits(char value) { - for (int i = 1 /*upper*/; i < words(); i++) m_value[i] = {0, 0}; - m_value[0] = {(value == '1' || value == 'x' || value == 1 || value == 3), - (value == 'z' || value == 'x' || value == 2 || value == 3)}; + for (int i = 1 /*upper*/; i < words(); i++) m_data.num()[i] = {0, 0}; + m_data.num()[0] = {(value == '1' || value == 'x' || value == 1 || value == 3), + (value == 'z' || value == 'x' || value == 2 || value == 3)}; return *this; } V3Number& V3Number::setAllBits0() { - for (int i = 0; i < words(); i++) m_value[i] = {0, 0}; + for (int i = 0; i < words(); i++) m_data.num()[i] = {0, 0}; return *this; } V3Number& V3Number::setAllBits1() { - for (int i = 0; i < words(); i++) m_value[i] = {~0U, 0}; + for (int i = 0; i < words(); i++) m_data.num()[i] = {~0U, 0}; opCleanThis(); return *this; } V3Number& V3Number::setAllBitsX() { // Use setAllBitsXRemoved if calling this based on a non-X/Z input value such as divide by zero - for (int i = 0; i < words(); i++) m_value[i] = {~0U, ~0U}; + for (int i = 0; i < words(); i++) m_data.num()[i] = {~0U, ~0U}; opCleanThis(); return *this; } V3Number& V3Number::setAllBitsZ() { - for (int i = 0; i < words(); i++) m_value[i] = {0, ~0U}; + for (int i = 0; i < words(); i++) m_data.num()[i] = {0, ~0U}; opCleanThis(); return *this; } @@ -491,7 +496,7 @@ string V3Number::ascii(bool prefixed, bool cleanVerilog) const { } else if (isString()) { return '"' + toString() + '"'; } else { - if (VL_UNCOVERABLE((m_value[words() - 1].m_value | m_value[words() - 1].m_valueX) + if (VL_UNCOVERABLE((m_data.num()[words() - 1].m_value | m_data.num()[words() - 1].m_valueX) & ~hiWordMask())) { out << "%E-hidden-bits"; // LCOV_EXCL_LINE } @@ -686,7 +691,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const { } case 's': { // Spec says always drop leading zeros, this isn't quite right, we space pad. - int bit = this->width() - 1; + int bit = width() - 1; bool start = true; while ((bit % 8) != 7) bit++; for (; bit >= 0; bit -= 8) { @@ -698,7 +703,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const { if (fmtsize != "0") str += ' '; } } - const size_t fmtsizen = static_cast(atoi(fmtsize.c_str())); + const size_t fmtsizen = static_cast(std::atoi(fmtsize.c_str())); str = displayPad(fmtsizen, ' ', left, str); return str; } @@ -707,7 +712,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const { case 'd': { // Unsigned decimal const bool issigned = (code == '~'); if (fmtsize == "") { - const double mantissabits = this->width() - (issigned ? 1 : 0); + const double mantissabits = width() - (issigned ? 1 : 0); // To get the number of digits required, we want to compute // log10(2**mantissabits) and round it up. To be able to handle // a very wide mantissa, we use log2(2**mantissabits)/log2(10), @@ -747,7 +752,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const { } const bool zeropad = fmtsize.length() > 0 && fmtsize[0] == '0'; // fmtsize might have changed since we parsed the %fmtsize - const size_t fmtsizen = static_cast(atoi(fmtsize.c_str())); + const size_t fmtsizen = static_cast(std::atoi(fmtsize.c_str())); str = displayPad(fmtsizen, (zeropad ? '0' : ' '), left, str); return str; } @@ -763,7 +768,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const { // 'p' // Packed - converted to another code by V3Width case 'u': { // Packed 2-state for (int i = 0; i < words(); i++) { - const uint32_t v = m_value[i].m_value; + const uint32_t v = m_data.num()[i].m_value; str += static_cast((v >> 0) & 0xff); str += static_cast((v >> 8) & 0xff); str += static_cast((v >> 16) & 0xff); @@ -773,7 +778,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const { } case 'z': { // Packed 4-state for (int i = 0; i < words(); i++) { - const ValueAndX v = m_value[i]; + const ValueAndX v = m_data.num()[i]; str += static_cast((v.m_value >> 0) & 0xff); str += static_cast((v.m_value >> 8) & 0xff); str += static_cast((v.m_value >> 16) & 0xff); @@ -802,7 +807,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const { return str; } case '@': { // Packed string - const size_t fmtsizen = static_cast(atoi(fmtsize.c_str())); + const size_t fmtsizen = static_cast(std::atoi(fmtsize.c_str())); str = displayPad(fmtsizen, ' ', left, toString()); return str; } @@ -870,12 +875,12 @@ uint32_t V3Number::toUInt() const { UASSERT(!isFourState(), "toUInt with 4-state " << *this); // We allow wide numbers that represent values <= 32 bits for (int i = 1; i < words(); ++i) { - if (m_value[i].m_value) { + if (m_data.num()[i].m_value) { v3error("Value too wide for 32-bits expected in this context " << *this); break; } } - return m_value[0].m_value; + return m_data.num()[0].m_value; } double V3Number::toDouble() const { @@ -886,8 +891,8 @@ double V3Number::toDouble() const { double d; uint32_t u[2]; } u; - u.u[0] = m_value[0].m_value; - u.u[1] = m_value[1].m_value; + u.u[0] = m_data.num()[0].m_value; + u.u[1] = m_data.num()[1].m_value; return u.d; } @@ -909,14 +914,14 @@ uint64_t V3Number::toUQuad() const { // We allow wide numbers that represent values <= 64 bits if (isDouble()) return static_cast(toDouble()); for (int i = 2; i < words(); ++i) { - if (m_value[i].m_value) { + if (m_data.num()[i].m_value) { v3error("Value too wide for 64-bits expected in this context " << *this); break; } } if (width() <= 32) return (static_cast(toUInt())); - return ((static_cast(m_value[1].m_value) << 32ULL) - | (static_cast(m_value[0].m_value))); + return ((static_cast(m_data.num()[1].m_value) << 32ULL) + | (static_cast(m_data.num()[0].m_value))); } int64_t V3Number::toSQuad() const { @@ -930,8 +935,8 @@ int64_t V3Number::toSQuad() const { string V3Number::toString() const { UASSERT(!isFourState(), "toString with 4-state " << *this); // Spec says always drop leading zeros, this isn't quite right, we space pad. - if (isString()) return m_stringVal; - int bit = this->width() - 1; + if (isString()) return m_data.str(); + int bit = width() - 1; bool start = true; while ((bit % 8) != 7) bit++; string str; @@ -946,14 +951,18 @@ string V3Number::toString() const { } V3Hash V3Number::toHash() const { - V3Hash hash(m_width); - for (int i = 0; i < words(); ++i) { hash += m_value[i].m_value; } + V3Hash hash{width()}; + if (isString()) { + hash += V3Hash{m_data.str()}; + } else { + for (int i = 0; i < words(); ++i) { hash += m_data.num()[i].m_value; } + } return hash; } uint32_t V3Number::edataWord(int eword) const { UASSERT(!isFourState(), "edataWord with 4-state " << *this); - return m_value[eword].m_value; + return m_data.num()[eword].m_value; } uint8_t V3Number::dataByte(int byte) const { @@ -961,30 +970,34 @@ uint8_t V3Number::dataByte(int byte) const { } bool V3Number::isAllZ() const { + if (isDouble() || isString()) return false; for (int i = 0; i < width(); i++) { if (!bitIsZ(i)) return false; } return true; } bool V3Number::isAllX() const { + if (isDouble() || isString()) return false; uint32_t mask = hiWordMask(); for (int i = words() - 1; i >= 0; --i) { - const ValueAndX v = m_value[i]; + const ValueAndX v = m_data.num()[i]; if ((v.m_value & v.m_valueX) ^ mask) return false; mask = ~0U; } return true; } bool V3Number::isEqZero() const { + if (isString()) return m_data.str().empty(); for (int i = 0; i < words(); i++) { - const ValueAndX v = m_value[i]; + const ValueAndX v = m_data.num()[i]; if (v.m_value || v.m_valueX) return false; } return true; } bool V3Number::isNeqZero() const { + if (isString()) return !m_data.str().empty(); for (int i = 0; i < words(); i++) { - const ValueAndX v = m_value[i]; + const ValueAndX v = m_data.num()[i]; if (v.m_value & ~v.m_valueX) return true; } return false; @@ -996,9 +1009,9 @@ bool V3Number::isBitsZero(int msb, int lsb) const { return true; } bool V3Number::isEqOne() const { - if (m_value[0].m_value != 1 || m_value[0].m_valueX) return false; + if (m_data.num()[0].m_value != 1 || m_data.num()[0].m_valueX) return false; for (int i = 1; i < words(); i++) { - const ValueAndX v = m_value[i]; + const ValueAndX v = m_data.num()[i]; if (v.m_value || v.m_valueX) return false; } return true; @@ -1013,7 +1026,7 @@ bool V3Number::isEqAllOnes(int optwidth) const { bool V3Number::isFourState() const { if (isDouble() || isString()) return false; for (int i = 0; i < words(); ++i) { - if (m_value[i].m_valueX) return true; + if (m_data.num()[i].m_valueX) return true; } return false; } @@ -1034,10 +1047,10 @@ bool V3Number::isAnyZ() const { } bool V3Number::isLtXZ(const V3Number& rhs) const { // Include X/Z in comparisons for sort ordering - for (int bit = 0; bit < std::max(this->width(), rhs.width()); bit++) { - if (this->bitIs1(bit) && rhs.bitIs0(bit)) return true; - if (rhs.bitIs1(bit) && this->bitIs0(bit)) return false; - if (this->bitIsXZ(bit)) return true; + for (int bit = 0; bit < std::max(width(), rhs.width()); bit++) { + if (bitIs1(bit) && rhs.bitIs0(bit)) return true; + if (rhs.bitIs1(bit) && bitIs0(bit)) return false; + if (bitIsXZ(bit)) return true; if (rhs.bitIsXZ(bit)) return false; } return false; @@ -1068,7 +1081,7 @@ int V3Number::widthMin() const { uint32_t V3Number::countBits(const V3Number& ctrl) const { int n = 0; - for (int bit = 0; bit < this->width(); ++bit) { + for (int bit = 0; bit < width(); ++bit) { switch (ctrl.bitIs(0)) { case '0': if (bitIs0(bit)) ++n; @@ -1099,14 +1112,14 @@ uint32_t V3Number::countBits(const V3Number& ctrl1, const V3Number& ctrl2, uint32_t V3Number::countOnes() const { int n = 0; - for (int bit = 0; bit < this->width(); bit++) { + for (int bit = 0; bit < width(); bit++) { if (bitIs1(bit)) n++; } return n; } uint32_t V3Number::mostSetBitP1() const { - for (int bit = this->width() - 1; bit >= 0; bit--) { + for (int bit = width() - 1; bit >= 0; bit--) { if (bitIs1(bit)) return bit + 1; } return 0; @@ -1118,7 +1131,7 @@ V3Number& V3Number::opBitsNonX(const V3Number& lhs) { // 0/1->1, X/Z->0 NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_LOGIC_ARGS1(lhs); setZero(); - for (int bit = 0; bit < this->width(); bit++) { + for (int bit = 0; bit < width(); bit++) { if (lhs.bitIs0(bit) || lhs.bitIs1(bit)) setBit(bit, 1); } return *this; @@ -1128,7 +1141,7 @@ V3Number& V3Number::opBitsOne(const V3Number& lhs) { // 1->1, 0/X/Z->0 NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_LOGIC_ARGS1(lhs); setZero(); - for (int bit = 0; bit < this->width(); bit++) { + for (int bit = 0; bit < width(); bit++) { if (lhs.bitIs1(bit)) setBit(bit, 1); } return *this; @@ -1138,7 +1151,7 @@ V3Number& V3Number::opBitsXZ(const V3Number& lhs) { // 0/1->1, X/Z->0 NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_LOGIC_ARGS1(lhs); setZero(); - for (int bit = 0; bit < this->width(); bit++) { + for (int bit = 0; bit < width(); bit++) { if (lhs.bitIsXZ(bit)) setBit(bit, 1); } return *this; @@ -1148,7 +1161,7 @@ V3Number& V3Number::opBitsZ(const V3Number& lhs) { // 0/1->1, X/Z->0 NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_LOGIC_ARGS1(lhs); setZero(); - for (int bit = 0; bit < this->width(); bit++) { + for (int bit = 0; bit < width(); bit++) { if (lhs.bitIsZ(bit)) setBit(bit, 1); } return *this; @@ -1158,7 +1171,7 @@ V3Number& V3Number::opBitsNonZ(const V3Number& lhs) { // 0/1->1, X/Z->0 NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_LOGIC_ARGS1(lhs); setZero(); - for (int bit = 0; bit < this->width(); bit++) { + for (int bit = 0; bit < width(); bit++) { if (!lhs.bitIsZ(bit)) setBit(bit, 1); } return *this; @@ -1224,7 +1237,7 @@ V3Number& V3Number::opCountBits(const V3Number& expr, const V3Number& ctrl1, con NUM_ASSERT_OP_ARGS4(expr, ctrl1, ctrl2, ctrl3); NUM_ASSERT_LOGIC_ARGS4(expr, ctrl1, ctrl2, ctrl3); setZero(); - m_value[0].m_value = expr.countBits(ctrl1, ctrl2, ctrl3); + m_data.num()[0].m_value = expr.countBits(ctrl1, ctrl2, ctrl3); opCleanThis(); return *this; } @@ -1233,7 +1246,7 @@ V3Number& V3Number::opCountOnes(const V3Number& lhs) { NUM_ASSERT_LOGIC_ARGS1(lhs); if (lhs.isFourState()) return setAllBitsX(); setZero(); - m_value[0].m_value = lhs.countOnes(); + m_data.num()[0].m_value = lhs.countOnes(); opCleanThis(); return *this; } @@ -1290,7 +1303,7 @@ V3Number& V3Number::opNot(const V3Number& lhs) { NUM_ASSERT_LOGIC_ARGS1(lhs); // op i, L(lhs) bit return setZero(); - for (int bit = 0; bit < this->width(); bit++) { + for (int bit = 0; bit < width(); bit++) { if (lhs.bitIs0(bit)) { setBit(bit, 1); } else if (lhs.bitIsXZ(bit)) { @@ -1305,7 +1318,7 @@ V3Number& V3Number::opAnd(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); // i op j, max(L(lhs),L(rhs)) bit return, careful need to X/Z extend. setZero(); - for (int bit = 0; bit < this->width(); bit++) { + for (int bit = 0; bit < width(); bit++) { if (lhs.bitIs1(bit) && rhs.bitIs1(bit)) { setBit(bit, 1); } else if (lhs.bitIs0(bit) || rhs.bitIs0(bit)) { // 0 @@ -1321,7 +1334,7 @@ V3Number& V3Number::opOr(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); // i op j, max(L(lhs),L(rhs)) bit return, careful need to X/Z extend. setZero(); - for (int bit = 0; bit < this->width(); bit++) { + for (int bit = 0; bit < width(); bit++) { if (lhs.bitIs1(bit) || rhs.bitIs1(bit)) { setBit(bit, 1); } else if (lhs.bitIs0(bit) && rhs.bitIs0(bit)) { @@ -1338,7 +1351,7 @@ V3Number& V3Number::opXor(const V3Number& lhs, const V3Number& rhs) { NUM_ASSERT_OP_ARGS2(lhs, rhs); NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); setZero(); - for (int bit = 0; bit < this->width(); bit++) { + for (int bit = 0; bit < width(); bit++) { if (lhs.bitIs1(bit) && rhs.bitIs0(bit)) { setBit(bit, 1); } else if (lhs.bitIs0(bit) && rhs.bitIs1(bit)) { @@ -1617,9 +1630,9 @@ bool V3Number::isCaseEq(const V3Number& rhs) const { // i op j, 1 bit return, max(L(lhs),L(rhs)) calculation, careful need to X/Z extend. if (isString()) return toString() == rhs.toString(); if (isDouble()) return toDouble() == rhs.toDouble(); - if (this->width() != rhs.width()) return false; + if (width() != rhs.width()) return false; for (int i = 0; i < words(); ++i) { - if (!(m_value[i] == rhs.m_value[i])) return false; + if (!(m_data.num()[i] == rhs.m_data.num()[i])) return false; } return true; } @@ -1752,7 +1765,7 @@ V3Number& V3Number::opShiftR(const V3Number& lhs, const V3Number& rhs) { } const uint32_t rhsval = rhs.toUInt(); if (rhsval < static_cast(lhs.width())) { - for (int bit = 0; bit < this->width(); bit++) setBit(bit, lhs.bitIs(bit + rhsval)); + for (int bit = 0; bit < width(); bit++) setBit(bit, lhs.bitIs(bit + rhsval)); } return *this; } @@ -1766,7 +1779,7 @@ V3Number& V3Number::opShiftRS(const V3Number& lhs, const V3Number& rhs, uint32_t if (rhs.isFourState()) return setAllBitsX(); setZero(); for (int bit = 32; bit < rhs.width(); bit++) { - for (int sbit = 0; sbit < this->width(); sbit++) { + for (int sbit = 0; sbit < width(); sbit++) { setBit(sbit, lhs.bitIs(lbits - 1)); // 0/1/X/Z } if (rhs.bitIs1(lbits - 1)) setAllBits1(); // -1 else 0 @@ -1774,11 +1787,11 @@ V3Number& V3Number::opShiftRS(const V3Number& lhs, const V3Number& rhs, uint32_t } const uint32_t rhsval = rhs.toUInt(); if (rhsval < static_cast(lhs.width())) { - for (int bit = 0; bit < this->width(); bit++) { + for (int bit = 0; bit < width(); bit++) { setBit(bit, lhs.bitIsExtend(bit + rhsval, lbits)); } } else { - for (int bit = 0; bit < this->width(); bit++) { + for (int bit = 0; bit < width(); bit++) { setBit(bit, lhs.bitIs(lbits - 1)); // 0/1/X/Z } } @@ -1795,7 +1808,7 @@ V3Number& V3Number::opShiftL(const V3Number& lhs, const V3Number& rhs) { if (rhs.bitIs1(bit)) return *this; // shift of over 2^32 must be zero } const uint32_t rhsval = rhs.toUInt(); - for (int bit = 0; bit < this->width(); bit++) { + for (int bit = 0; bit < width(); bit++) { if (bit >= static_cast(rhsval)) setBit(bit, lhs.bitIs(bit - rhsval)); } return *this; @@ -1823,7 +1836,7 @@ V3Number& V3Number::opAdd(const V3Number& lhs, const V3Number& rhs) { setZero(); // Addem int carry = 0; - for (int bit = 0; bit < this->width(); bit++) { + for (int bit = 0; bit < width(); bit++) { const int sum = ((lhs.bitIs1(bit) ? 1 : 0) + (rhs.bitIs1(bit) ? 1 : 0) + carry); if (sum & 1) setBit(bit, 1); carry = (sum >= 2); @@ -1850,15 +1863,15 @@ V3Number& V3Number::opMul(const V3Number& lhs, const V3Number& rhs) { opCleanThis(); // Mult produces extra bits in result } else { for (int lword = 0; lword < lhs.words(); lword++) { - const uint64_t lwordval = static_cast(lhs.m_value[lword].m_value); + const uint64_t lwordval = static_cast(lhs.m_data.num()[lword].m_value); if (lwordval == 0) continue; for (int rword = 0; rword < rhs.words(); rword++) { - const uint64_t rwordval = static_cast(rhs.m_value[rword].m_value); + const uint64_t rwordval = static_cast(rhs.m_data.num()[rword].m_value); if (rwordval == 0) continue; uint64_t mul = lwordval * rwordval; - for (int qword = lword + rword; qword < this->words(); qword++) { - mul += static_cast(m_value[qword].m_value); - m_value[qword].m_value = (mul & 0xffffffffULL); + for (int qword = lword + rword; qword < words(); qword++) { + mul += static_cast(m_data.num()[qword].m_value); + m_data.num()[qword].m_value = (mul & 0xffffffffULL); mul = (mul >> 32ULL) & 0xffffffffULL; if (mul == 0) break; } @@ -1975,17 +1988,18 @@ V3Number& V3Number::opModDivGuts(const V3Number& lhs, const V3Number& rhs, bool if (vw == 1) { // Single divisor word breaks rest of algorithm uint64_t k = 0; for (int j = uw - 1; j >= 0; j--) { - const uint64_t unw64 = ((k << 32ULL) + static_cast(lhs.m_value[j].m_value)); - m_value[j].m_value = unw64 / static_cast(rhs.m_value[0].m_value); + const uint64_t unw64 + = ((k << 32ULL) + static_cast(lhs.m_data.num()[j].m_value)); + m_data.num()[j].m_value = unw64 / static_cast(rhs.m_data.num()[0].m_value); k = unw64 - - (static_cast(m_value[j].m_value) - * static_cast(rhs.m_value[0].m_value)); + - (static_cast(m_data.num()[j].m_value) + * static_cast(rhs.m_data.num()[0].m_value)); } UINFO(9, " opmoddiv-1w " << lhs << " " << rhs << " q=" << *this << " rem=0x" << std::hex << k << std::dec << endl); if (is_modulus) { setZero(); - m_value[0].m_value = k; + m_data.num()[0].m_value = k; } opCleanThis(); return *this; @@ -1996,7 +2010,7 @@ V3Number& V3Number::opModDivGuts(const V3Number& lhs, const V3Number& rhs, bool uint32_t vn[VL_MULS_MAX_WORDS + 1]; // v normalized // Zero for ease of debugging and to save having to zero for shifts - for (int i = 0; i < words; i++) { m_value[i].m_value = 0; } + for (int i = 0; i < words; i++) { m_data.num()[i].m_value = 0; } for (int i = 0; i < words + 1; i++) { un[i] = vn[i] = 0; } // +1 as vn may get extra word // Algorithm requires divisor MSB to be set @@ -2004,22 +2018,22 @@ V3Number& V3Number::opModDivGuts(const V3Number& lhs, const V3Number& rhs, bool const int s = 31 - ((vmsbp1 - 1) & 31); // shift amount (0...31) const uint32_t shift_mask = s ? 0xffffffff : 0; // otherwise >> 32 won't mask the value for (int i = vw - 1; i > 0; i--) { - vn[i] = (rhs.m_value[i].m_value << s) - | (shift_mask & (rhs.m_value[i - 1].m_value >> (32 - s))); + vn[i] = (rhs.m_data.num()[i].m_value << s) + | (shift_mask & (rhs.m_data.num()[i - 1].m_value >> (32 - s))); } - vn[0] = rhs.m_value[0].m_value << s; + vn[0] = rhs.m_data.num()[0].m_value << s; // Copy and shift dividend by same amount; may set new upper word if (s) { - un[uw] = lhs.m_value[uw - 1].m_value >> (32 - s); + un[uw] = lhs.m_data.num()[uw - 1].m_value >> (32 - s); } else { un[uw] = 0; } for (int i = uw - 1; i > 0; i--) { - un[i] = (lhs.m_value[i].m_value << s) - | (shift_mask & (lhs.m_value[i - 1].m_value >> (32 - s))); + un[i] = (lhs.m_data.num()[i].m_value << s) + | (shift_mask & (lhs.m_data.num()[i - 1].m_value >> (32 - s))); } - un[0] = lhs.m_value[0].m_value << s; + un[0] = lhs.m_data.num()[0].m_value << s; // printf(" un="); for (int i=5; i>=0; i--) printf(" %08x",un[i]); printf("\n"); // printf(" vn="); for (int i=5; i>=0; i--) printf(" %08x",vn[i]); printf("\n"); @@ -2050,11 +2064,11 @@ V3Number& V3Number::opModDivGuts(const V3Number& lhs, const V3Number& rhs, bool } t = un[j + vw] - k; un[j + vw] = t; - this->m_value[j].m_value = qhat; // Save quotient digit + m_data.num()[j].m_value = qhat; // Save quotient digit if (t < 0) { // Over subtracted; correct by adding back - this->m_value[j].m_value--; + m_data.num()[j].m_value--; k = 0; for (int i = 0; i < vw; i++) { t = static_cast(un[i + j]) + static_cast(vn[i]) + k; @@ -2072,9 +2086,9 @@ V3Number& V3Number::opModDivGuts(const V3Number& lhs, const V3Number& rhs, bool if (is_modulus) { // modulus // Need to reverse normalization on copy to output for (int i = 0; i < vw; i++) { - m_value[i].m_value = (un[i] >> s) | (shift_mask & (un[i + 1] << (32 - s))); + m_data.num()[i].m_value = (un[i] >> s) | (shift_mask & (un[i + 1] << (32 - s))); } - for (int i = vw; i < words; i++) m_value[i].m_value = 0; + for (int i = vw; i < words; i++) m_data.num()[i].m_value = 0; opCleanThis(); UINFO(9, " opmoddiv-mod " << lhs << " " << rhs << " now=" << *this << endl); return *this; @@ -2108,7 +2122,7 @@ V3Number& V3Number::opPow(const V3Number& lhs, const V3Number& rhs, bool lsign, } if (lhs.isEqZero()) return setZero(); setZero(); - m_value[0].m_value = 1; + m_data.num()[0].m_value = 1; V3Number power(&lhs, width()); power.opAssign(lhs); for (int bit = 0; bit < rhs.width(); bit++) { @@ -2120,7 +2134,7 @@ V3Number& V3Number::opPow(const V3Number& lhs, const V3Number& rhs, bool lsign, if (rhs.bitIs1(bit)) { // out *= power V3Number lastOut(&lhs, width()); lastOut.opAssign(*this); - this->opMul(lastOut, power); + opMul(lastOut, power); // UINFO(0, "pow "<width(); bit++) { @@ -2196,14 +2217,14 @@ V3Number& V3Number::opClean(const V3Number& lhs, uint32_t bits) { return opSel(l void V3Number::opCleanThis(bool warnOnTruncation) { // Clean MSB of number NUM_ASSERT_LOGIC_ARGS1(*this); - const ValueAndX v = m_value[words() - 1]; + const ValueAndX v = m_data.num()[words() - 1]; const uint32_t newValueMsb = v.m_value & hiWordMask(); const uint32_t newValueXMsb = v.m_valueX & hiWordMask(); if (warnOnTruncation && (newValueMsb != v.m_value || newValueXMsb != v.m_valueX)) { // Displaying in decimal avoids hiWordMask truncation v3warn(WIDTH, "Value too large for " << width() << " bit number: " << displayed("%d")); } - m_value[words() - 1] = {newValueMsb, newValueXMsb}; + m_data.num()[words() - 1] = {newValueMsb, newValueXMsb}; } V3Number& V3Number::opSel(const V3Number& lhs, const V3Number& msb, const V3Number& lsb) { @@ -2219,7 +2240,7 @@ V3Number& V3Number::opSel(const V3Number& lhs, uint32_t msbval, uint32_t lsbval) NUM_ASSERT_LOGIC_ARGS1(lhs); setZero(); int ibit = lsbval; - for (int bit = 0; bit < this->width(); bit++) { + for (int bit = 0; bit < width(); bit++) { if (ibit >= 0 && ibit < lhs.width() && ibit <= static_cast(msbval)) { setBit(bit, lhs.bitIs(ibit)); } else { @@ -2315,21 +2336,17 @@ V3Number& V3Number::opRealToBits(const V3Number& lhs) { NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_DOUBLE_ARGS1(lhs); // Conveniently our internal format is identical so we can copy bits... - if (lhs.width() != 64 || this->width() != 64) { - v3fatalSrc("Real operation on wrong sized number"); - } + if (lhs.width() != 64 || width() != 64) v3fatalSrc("Real operation on wrong sized number"); + m_data.setLogic(); opAssign(lhs); - m_double = false; return *this; } V3Number& V3Number::opBitsToRealD(const V3Number& lhs) { NUM_ASSERT_OP_ARGS1(lhs); // Conveniently our internal format is identical so we can copy bits... - if (lhs.width() != 64 || this->width() != 64) { - v3fatalSrc("Real operation on wrong sized number"); - } + if (lhs.width() != 64 || width() != 64) v3fatalSrc("Real operation on wrong sized number"); + m_data.setDouble(); opAssign(lhs); - m_double = true; return *this; } V3Number& V3Number::opNegateD(const V3Number& lhs) { diff --git a/src/V3Number.h b/src/V3Number.h index fe2f11c5d..f149c6ae6 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -22,8 +22,10 @@ #include "V3Error.h" #include "V3Hash.h" +#include "V3StdFuture.h" #include +#include #include #include #include @@ -42,8 +44,6 @@ class AstNode; class AstNodeDType; class FileLine; -// Holds a few entries of ValueAndX to avoid dynamic allocation in std::vector for less width of -// constants class V3NumberData final { public: // TYPES @@ -57,53 +57,294 @@ public: } }; + enum class V3NumberDataType : uint8_t { + UNINITIALIZED = 0, + LOGIC = 1, + DOUBLE = 2, + STRING = 3, + }; + friend std::ostream& operator<<(std::ostream& os, const V3NumberDataType& rhs) { + switch (rhs) { + case V3NumberDataType::UNINITIALIZED: return os << "UNINITIALIZED"; + case V3NumberDataType::LOGIC: return os << "LOGIC"; + case V3NumberDataType::DOUBLE: return os << "DOUBLE"; + case V3NumberDataType::STRING: return os << "STRING"; + } + return os; + } + private: + // CONSTANTS + // At least 2 words (64 fourstate bits). 4 words (128 fourstate bits) in most cases, + // i.e. when std::string has 32 bytes. + static constexpr int INLINE_WORDS = vlstd::max( + static_cast(2), vlstd::max(sizeof(std::string) / sizeof(ValueAndX), + sizeof(std::vector) / sizeof(ValueAndX))); + // When m_width > MAX_INLINE_WIDTH number is stored in m_dynamicNumber. + // Otherwise number is stored in m_inlineNumber. + static constexpr int MAX_INLINE_WIDTH = INLINE_WORDS * sizeof(ValueAndX) / 2 * 8; + // MEMBERS - static constexpr size_t m_inlinedSize = 2; // Can hold 64 bit without dynamic allocation - ValueAndX m_inlined[m_inlinedSize]; // Holds the beginning m_inlinedSize words - std::vector m_data; // Holds m_inlinedSize-th word and later + union { + std::array m_inlineNumber; + std::vector m_dynamicNumber; + std::string m_string; + }; + + int m_width = 0; // Width (in bits) as specified/calculated + V3NumberDataType m_type; + +public: + bool m_sized : 1; // True if the user specified the width, else we track it. + bool m_signed : 1; // True if signed value + bool m_isNull : 1; // True if "null" versus normal 0 + bool m_fromString : 1; // True if from string literal + bool m_autoExtend : 1; // True if SystemVerilog extend-to-any-width public: // CONSTRUCTORS - V3NumberData() { - for (size_t i = 0; i < m_inlinedSize; ++i) m_inlined[i] = {0, 0}; + V3NumberData() + : m_type{V3NumberDataType::UNINITIALIZED} + , m_sized{false} + , m_signed{false} + , m_isNull{false} + , m_fromString{false} + , m_autoExtend{false} {} + + ~V3NumberData() { destroyStoredValue(); } + + V3NumberData(const V3NumberData& other) + : m_width{other.m_width} + , m_type{other.m_type} + , m_sized{other.m_sized} + , m_signed{other.m_signed} + , m_isNull{other.m_isNull} + , m_fromString{other.m_fromString} + , m_autoExtend{other.m_autoExtend} { + if (other.isInlineNumber()) { + initInlineNumber(other.m_inlineNumber); + } else if (other.isDynamicNumber()) { + initDynamicNumber(other.m_dynamicNumber); + } else if (other.isString()) { + initString(other.m_string); + } } + V3NumberData& operator=(const V3NumberData& other) { + if (other.isInlineNumber()) { + destroyStoredValue(); + initInlineNumber(other.m_inlineNumber); + } else if (other.isDynamicNumber()) { + reinitWithOrAssignDynamicNumber(other.m_dynamicNumber); + } else if (other.isString()) { + reinitWithOrAssignString(other.m_string); + } else { + destroyStoredValue(); + } + m_width = other.m_width; + m_type = other.m_type; + m_sized = other.m_sized; + m_signed = other.m_signed; + m_isNull = other.m_isNull; + m_fromString = other.m_fromString; + m_autoExtend = other.m_autoExtend; + return *this; + } + + V3NumberData(V3NumberData&& other) + : m_width{other.m_width} + , m_type{other.m_type} + , m_sized{other.m_sized} + , m_signed{other.m_signed} + , m_isNull{other.m_isNull} + , m_fromString{other.m_fromString} + , m_autoExtend{other.m_autoExtend} { + if (other.isInlineNumber()) { + initInlineNumber(other.m_inlineNumber); + } else if (other.isDynamicNumber()) { + initDynamicNumber(std::move(other.m_dynamicNumber)); + } else if (other.isString()) { + initString(std::move(other.m_string)); + } + other.m_type = V3NumberDataType::UNINITIALIZED; + } + + V3NumberData& operator=(V3NumberData&& other) { + if (other.isInlineNumber()) { + destroyStoredValue(); + initInlineNumber(other.m_inlineNumber); + } else if (other.isDynamicNumber()) { + reinitWithOrAssignDynamicNumber(std::move(other.m_dynamicNumber)); + } else if (other.isString()) { + reinitWithOrAssignString(std::move(other.m_string)); + } else { + destroyStoredValue(); + } + m_width = other.m_width; + m_type = other.m_type; + m_sized = other.m_sized; + m_signed = other.m_signed; + m_isNull = other.m_isNull; + m_fromString = other.m_fromString; + m_autoExtend = other.m_autoExtend; + other.m_type = V3NumberDataType::UNINITIALIZED; + return *this; + } + + // ACCESSORS + ValueAndX* num() { + UASSERT(isNumber(), "`num` member accessed when data type is " << m_type); + return isInlineNumber() ? m_inlineNumber.data() : m_dynamicNumber.data(); + } + const ValueAndX* num() const { + UASSERT(isNumber(), "`num` member accessed when data type is " << m_type); + return isInlineNumber() ? m_inlineNumber.data() : m_dynamicNumber.data(); + } + std::string& str() { + UASSERT(isString(), "`str` member accessed when data type is " << m_type); + return m_string; + } + const std::string& str() const { + UASSERT(isString(), "`str` member accessed when data type is " << m_type); + return m_string; + } + + int width() const { return m_width; } + V3NumberDataType type() const { return m_type; } + // METHODS - void ensureSizeAtLeast(size_t s) { - if (VL_UNLIKELY(s > m_data.size() + m_inlinedSize)) m_data.resize(s - m_inlinedSize); + void resize(int bitsCount) { + if (m_width == bitsCount) return; + if (bitsToWords(m_width) == bitsToWords(bitsCount)) { + m_width = bitsCount; + return; + } + if (isDynamicNumber()) { + if (bitsCount > MAX_INLINE_WIDTH) { + m_dynamicNumber.resize(bitsToWords(bitsCount)); + } else { + const auto dynamicBits = std::move(m_dynamicNumber); + destroyDynamicNumber(); + initInlineNumber(); + std::memcpy(m_inlineNumber.data(), dynamicBits.data(), sizeof(m_inlineNumber)); + } + } else if (isInlineNumber()) { + if (bitsCount > MAX_INLINE_WIDTH) { + const auto bits = m_inlineNumber; + initDynamicNumber(bitsToWords(bitsCount)); + std::memcpy(m_dynamicNumber.data(), bits.data(), sizeof(bits)); + } + } + m_width = bitsCount; } - ValueAndX& operator[](size_t idx) { - UDEBUGONLY(UASSERT(idx < m_data.size() + m_inlinedSize, - "idx:" << idx << " size:" << m_data.size() - << " inlinedSize:" << m_inlinedSize);); - return idx >= m_inlinedSize ? m_data[idx - m_inlinedSize] : m_inlined[idx]; + + void setString() { + // If there has been a string already it is kept intact. + if (isString()) return; + if (isDynamicNumber()) destroyDynamicNumber(); + initString(); + m_type = V3NumberDataType::STRING; + } + void setString(std::string&& s) { + reinitWithOrAssignString(std::move(s)); + m_type = V3NumberDataType::STRING; + } + void setString(const std::string& s) { + reinitWithOrAssignString(s); + m_type = V3NumberDataType::STRING; + } + + void setDouble() { + destroyStoredValue(); + if (!isInlineNumber()) initInlineNumber(); + m_type = V3NumberDataType::DOUBLE; + resize(64); + } + + void setLogic() { + if (isString()) destroyString(); + if (!isNumber()) { + if (m_width <= MAX_INLINE_WIDTH) { + initInlineNumber(); + } else { + initDynamicNumber(bitsToWords(m_width)); + } + } + m_type = V3NumberDataType::LOGIC; + resize(m_width); + } + +private: + static constexpr int bitsToWords(int bitsCount) { return (bitsCount + 31) / 32; } + + bool isNumber() const { + return m_type == V3NumberDataType::DOUBLE || m_type == V3NumberDataType::LOGIC; + } + bool isInlineNumber() const { + return (m_width <= MAX_INLINE_WIDTH) + && (m_type == V3NumberDataType::DOUBLE || m_type == V3NumberDataType::LOGIC); + } + bool isDynamicNumber() const { + return (m_width > MAX_INLINE_WIDTH) && (m_type == V3NumberDataType::LOGIC); + } + bool isString() const { return m_type == V3NumberDataType::STRING; } + + template + void initInlineNumber(Args&&... args) { + new (&m_inlineNumber) std::array(std::forward(args)...); + } + template + void initDynamicNumber(Args&&... args) { + new (&m_dynamicNumber) std::vector(std::forward(args)...); + } + template + void initString(Args&&... args) { + new (&m_string) std::string(std::forward(args)...); + } + + void destroyDynamicNumber() { m_dynamicNumber.~vector(); } + void destroyString() { m_string.~string(); } + void destroyStoredValue() { + if (isString()) + destroyString(); + else if (isDynamicNumber()) + destroyDynamicNumber(); + } + + template + void reinitWithOrAssignDynamicNumber(T&& s) { + if (isDynamicNumber()) { + m_dynamicNumber = std::forward(s); + return; + } + if (isString()) destroyString(); + initDynamicNumber(std::forward(s)); + } + template + void reinitWithOrAssignString(T&& s) { + if (isString()) { + m_string = std::forward(s); + return; + } + if (isDynamicNumber()) destroyDynamicNumber(); + initString(std::forward(s)); } - const ValueAndX& operator[](size_t idx) const { return const_cast(*this)[idx]; } }; class V3Number final { // TYPES using ValueAndX = V3NumberData::ValueAndX; + using V3NumberDataType = V3NumberData::V3NumberDataType; + + // MEMBERS + V3NumberData m_data; + AstNode* m_nodep = nullptr; // Parent node + FileLine* m_fileline = nullptr; - // Large 4-state number handling - int m_width; // Width as specified/calculated. - bool m_sized : 1; // True if the user specified the width, else we track it. - bool m_signed : 1; // True if signed value - bool m_double : 1; // True if double real value - bool m_isNull : 1; // True if "null" versus normal 0 - bool m_isString : 1; // True if string - bool m_fromString : 1; // True if from string literal - bool m_autoExtend : 1; // True if SystemVerilog extend-to-any-width - FileLine* m_fileline; - AstNode* m_nodep; // Parent node - V3NumberData m_value; // Value and X/Z information - string m_stringVal; // If isString, the value of the string // METHODS V3Number& setSingleBits(char value); V3Number& setString(const string& str) { - m_isString = true; - m_stringVal = str; + m_data.setString(str); return *this; } void opCleanThis(bool warnOnTruncation = false); @@ -116,10 +357,10 @@ public: V3Number& setLong(uint32_t value); V3Number& setLongS(int32_t value); V3Number& setDouble(double value); - void setBit(int bit, char value) { // Note must be pre-zeroed! - if (bit >= m_width) return; + void setBit(int bit, char value) { // Note: must be initialized as number and pre-zeroed! + if (bit >= m_data.width()) return; const uint32_t mask = (1UL << (bit & 31)); - ValueAndX& v = m_value[bit / 32]; + ValueAndX& v = m_data.num()[bit / 32]; if (value == '0' || value == 0) { v.m_value &= ~mask; v.m_valueX &= ~mask; @@ -137,65 +378,71 @@ public: private: char bitIs(int bit) const { - if (bit >= m_width || bit < 0) { + if (bit >= m_data.width() || bit < 0) { // We never sign extend return '0'; } - const ValueAndX v = m_value[bit / 32]; + const ValueAndX v = m_data.num()[bit / 32]; return ("01zx"[(((v.m_value & (1UL << (bit & 31))) ? 1 : 0) | ((v.m_valueX & (1UL << (bit & 31))) ? 2 : 0))]); } char bitIsExtend(int bit, int lbits) const { // lbits usually = width, but for C optimizations width=32_bits, lbits = 32_or_less if (bit < 0) return '0'; - UASSERT(lbits <= m_width, "Extend of wrong size"); + UASSERT(lbits <= m_data.width(), "Extend of wrong size"); if (bit >= lbits) { bit = lbits ? lbits - 1 : 0; - const ValueAndX v = m_value[bit / 32]; + const ValueAndX v = m_data.num()[bit / 32]; // We do sign extend return ("01zx"[(((v.m_value & (1UL << (bit & 31))) ? 1 : 0) | ((v.m_valueX & (1UL << (bit & 31))) ? 2 : 0))]); } - const ValueAndX v = m_value[bit / 32]; + const ValueAndX v = m_data.num()[bit / 32]; return ("01zx"[(((v.m_value & (1UL << (bit & 31))) ? 1 : 0) | ((v.m_valueX & (1UL << (bit & 31))) ? 2 : 0))]); } public: bool bitIs0(int bit) const { + if (!isNumber()) return false; if (bit < 0) return false; - if (bit >= m_width) return !bitIsXZ(m_width - 1); - const ValueAndX v = m_value[bit / 32]; + if (bit >= m_data.width()) return !bitIsXZ(m_data.width() - 1); + const ValueAndX v = m_data.num()[bit / 32]; return ((v.m_value & (1UL << (bit & 31))) == 0 && !(v.m_valueX & (1UL << (bit & 31)))); } bool bitIs1(int bit) const { + if (!isNumber()) return false; if (bit < 0) return false; - if (bit >= m_width) return false; - const ValueAndX v = m_value[bit / 32]; + if (bit >= m_data.width()) return false; + const ValueAndX v = m_data.num()[bit / 32]; return ((v.m_value & (1UL << (bit & 31))) && !(v.m_valueX & (1UL << (bit & 31)))); } bool bitIs1Extend(int bit) const { + if (!isNumber()) return false; if (bit < 0) return false; - if (bit >= m_width) return bitIs1Extend(m_width - 1); - const ValueAndX v = m_value[bit / 32]; + if (bit >= m_data.width()) return bitIs1Extend(m_data.width() - 1); + const ValueAndX v = m_data.num()[bit / 32]; return ((v.m_value & (1UL << (bit & 31))) && !(v.m_valueX & (1UL << (bit & 31)))); } bool bitIsX(int bit) const { + if (!isNumber()) return false; if (bit < 0) return false; - if (bit >= m_width) return bitIsZ(m_width - 1); - const ValueAndX v = m_value[bit / 32]; + if (bit >= m_data.width()) return bitIsZ(m_data.width() - 1); + const ValueAndX v = m_data.num()[bit / 32]; return ((v.m_value & (1UL << (bit & 31))) && (v.m_valueX & (1UL << (bit & 31)))); } bool bitIsXZ(int bit) const { + if (!isNumber()) return false; if (bit < 0) return false; - if (bit >= m_width) return bitIsXZ(m_width - 1); - const ValueAndX v = m_value[bit / 32]; + if (bit >= m_data.width()) return bitIsXZ(m_data.width() - 1); + const ValueAndX v = m_data.num()[bit / 32]; return ((v.m_valueX & (1UL << (bit & 31)))); } bool bitIsZ(int bit) const { + if (!isNumber()) return false; if (bit < 0) return false; - if (bit >= m_width) return bitIsZ(m_width - 1); - const ValueAndX v = m_value[bit / 32]; + if (bit >= m_data.width()) return bitIsZ(m_data.width() - 1); + const ValueAndX v = m_data.num()[bit / 32]; return ((~v.m_value & (1UL << (bit & 31))) && (v.m_valueX & (1UL << (bit & 31)))); } @@ -217,10 +464,12 @@ private: public: // CONSTRUCTORS explicit V3Number(AstNode* nodep) { init(nodep, 1); } - V3Number(AstNode* nodep, int width) { init(nodep, width); } // 0=unsized + V3Number(AstNode* nodep, int width) { // 0=unsized + init(nodep, width, width > 0); + } V3Number(AstNode* nodep, int width, uint32_t value, bool sized = true) { init(nodep, width, sized); - m_value[0].m_value = value; + m_data.num()[0].m_value = value; opCleanThis(); } // Create from a verilog 32'hxxxx number. @@ -233,15 +482,16 @@ public: V3Number(VerilogStringLiteral, AstNode* nodep, const string& str); class String {}; V3Number(String, AstNode* nodep, const string& value) { - init(nodep, 0); + init(nodep); setString(value); - m_fromString = true; + m_data.m_fromString = true; } class Null {}; V3Number(Null, AstNode* nodep) { - init(nodep, 0); - m_isNull = true; - m_autoExtend = true; + init(nodep); + m_data.setLogic(); + m_data.m_isNull = true; + m_data.m_autoExtend = true; } explicit V3Number(const V3Number* nump, int width = 1) { init(nullptr, width); @@ -249,7 +499,7 @@ public: } V3Number(const V3Number* nump, int width, uint32_t value) { init(nullptr, width); - m_value[0].m_value = value; + m_data.num()[0].m_value = value; opCleanThis(); m_fileline = nump->fileline(); } @@ -259,19 +509,31 @@ public: } V3Number(AstNode* nodep, const AstNodeDType* nodedtypep); + V3Number(const V3Number& other) = default; + V3Number& operator=(const V3Number& other) = default; + + V3Number(V3Number&& other) = default; + V3Number& operator=(V3Number&& other) = default; + + ~V3Number() {} + private: void V3NumberCreate(AstNode* nodep, const char* sourcep, FileLine* fl); - void init(AstNode* nodep, int swidth, bool sized = true) { + void init(AstNode* nodep, int swidth = -1, bool sized = true) { setNames(nodep); - // dtype info does NOT from nodep's dtype; nodep only for error reporting - m_signed = false; - m_double = false; - m_isNull = false; - m_isString = false; - m_autoExtend = false; - m_fromString = false; - width(swidth, sized); - for (int i = 0; i < words(); ++i) m_value[i] = {0, 0}; + if (swidth >= 0) { + if (swidth == 0) { + swidth = 1; + sized = false; + } + m_data.setLogic(); + m_data.resize(swidth); + m_data.m_sized = sized; + for (int i = 0; i < words(); ++i) m_data.num()[i] = {0, 0}; + } else { + m_data.resize(1); + m_data.m_sized = false; + } } void setNames(AstNode* nodep); static string displayPad(size_t fmtsize, char pad, bool left, const string& in); @@ -282,15 +544,8 @@ public: void v3errorEnd(std::ostringstream& sstr) const; void v3errorEndFatal(std::ostringstream& sstr) const VL_ATTR_NORETURN; void width(int width, bool sized = true) { - // Set width. Only set m_width here, as we need to tweak vector size - if (width) { - m_sized = sized; - m_width = width; - } else { - m_sized = false; - m_width = 1; - } - m_value.ensureSizeAtLeast(words()); + m_data.m_sized = sized; + m_data.resize(width); } // SETTERS @@ -305,25 +560,39 @@ public: string ascii(bool prefixed = true, bool cleanVerilog = false) const; string displayed(AstNode* nodep, const string& vformat) const; static bool displayedFmtLegal(char format, bool isScan); // Is this a valid format letter? - int width() const { return m_width; } + int width() const { return m_data.width(); } int widthMin() const; // Minimum width that can represent this number (~== log2(num)+1) - bool sized() const { return m_sized; } - bool autoExtend() const { return m_autoExtend; } - bool isFromString() const { return m_fromString; } + bool sized() const { return m_data.m_sized; } + bool autoExtend() const { return m_data.m_autoExtend; } + bool isFromString() const { return m_data.m_fromString; } + V3NumberDataType dataType() const { return m_data.type(); } + void dataType(V3NumberDataType newType) { + if (dataType() == newType) return; + UASSERT(newType != V3NumberDataType::UNINITIALIZED, "Can't set type to UNINITIALIZED."); + switch (newType) { + case V3NumberDataType::STRING: m_data.setString(); break; + case V3NumberDataType::DOUBLE: m_data.setDouble(); break; + case V3NumberDataType::LOGIC: m_data.setLogic(); break; + case V3NumberDataType::UNINITIALIZED: break; + } + } // Only correct for parsing of numbers from strings, otherwise not used // (use AstConst::isSigned()) - bool isSigned() const { return m_signed; } - // Only correct for parsing of numbers from strings, otherwise not used - // (use AstConst::isSigned()) - bool isDouble() const { return m_double; } - // Only if have 64 bit value loaded, and want to indicate it's real - bool isString() const { return m_isString; } - bool isNegative() const { return bitIs1(width() - 1); } - bool isNull() const { return m_isNull; } + bool isSigned() const { return m_data.m_signed; } + void isSigned(bool ssigned) { m_data.m_signed = ssigned; } + bool isDouble() const { return dataType() == V3NumberDataType::DOUBLE; } + bool isString() const { return dataType() == V3NumberDataType::STRING; } + bool isNumber() const { + return m_data.type() == V3NumberDataType::LOGIC + || m_data.type() == V3NumberDataType::DOUBLE; + } + bool isNegative() const { return !isString() && bitIs1(width() - 1); } + bool isNull() const { return m_data.m_isNull; } bool isFourState() const; bool hasZ() const { + if (isString()) return false; for (int i = 0; i < words(); i++) { - const ValueAndX v = m_value[i]; + const ValueAndX v = m_data.num()[i]; if ((~v.m_value) & v.m_valueX) return true; } return false; @@ -337,11 +606,10 @@ public: bool isEqAllOnes(int optwidth = 0) const; bool isCaseEq(const V3Number& rhs) const; // operator== bool isLtXZ(const V3Number& rhs) const; // operator< with XZ compared - void isSigned(bool ssigned) { m_signed = ssigned; } bool isAnyX() const; bool isAnyXZ() const; bool isAnyZ() const; - bool isMsbXZ() const { return bitIsXZ(m_width - 1); } + bool isMsbXZ() const { return bitIsXZ(m_data.width() - 1); } uint32_t toUInt() const; int32_t toSInt() const; uint64_t toUQuad() const; diff --git a/src/V3OptionParser.cpp b/src/V3OptionParser.cpp index 308a26e10..1a1f7d84a 100644 --- a/src/V3OptionParser.cpp +++ b/src/V3OptionParser.cpp @@ -39,12 +39,12 @@ struct V3OptionParser::Impl { class ActionBase VL_NOT_FINAL : public ActionIfs { bool m_undocumented = false; // This option is not documented public: - virtual bool isValueNeeded() const override final { return MODE == en::VALUE; } - virtual bool isFOnOffAllowed() const override final { return MODE == en::FONOFF; } - virtual bool isOnOffAllowed() const override final { return MODE == en::ONOFF; } - virtual bool isPartialMatchAllowed() const override final { return ALLOW_PARTIAL_MATCH; } - virtual bool isUndocumented() const override { return m_undocumented; } - virtual void undocumented() override { m_undocumented = true; } + bool isValueNeeded() const override final { return MODE == en::VALUE; } + bool isFOnOffAllowed() const override final { return MODE == en::FONOFF; } + bool isOnOffAllowed() const override final { return MODE == en::ONOFF; } + bool isPartialMatchAllowed() const override final { return ALLOW_PARTIAL_MATCH; } + bool isUndocumented() const override { return m_undocumented; } + void undocumented() override { m_undocumented = true; } }; // Actual action classes @@ -78,7 +78,7 @@ struct V3OptionParser::Impl { public: \ explicit className(type* valp) \ : m_valp(valp) {} \ - virtual void exec(const char* optp, const char* argp) override { body; } \ + void exec(const char* optp, const char* argp) override { body; } \ } V3OPTION_PARSER_DEF_ACT_CLASS(ActionSet, bool, *m_valp = true, en::NONE); @@ -104,7 +104,7 @@ V3OPTION_PARSER_DEF_ACT_CLASS(ActionOnOff, VOptionBool, m_valp->setTrueOrFalse(! using CbType = std::function; \ explicit className(CbType cb) \ : m_cb(std::move(cb)) {} \ - virtual void exec(const char* optp, const char* argp) override { body; } \ + void exec(const char* optp, const char* argp) override { body; } \ } V3OPTION_PARSER_DEF_ACT_CB_CLASS(ActionCbCall, void(void), m_cb(), en::NONE); @@ -130,8 +130,8 @@ V3OptionParser::ActionIfs* V3OptionParser::find(const char* optp) { for (auto&& act : m_pimpl->m_options) { if (act.second->isFOnOffAllowed()) { // Find starts with "-fno" if (const char* const nop - = VString::startsWith(optp, "-fno-") ? (optp + strlen("-fno-")) : nullptr) { - if (act.first.substr(strlen("-f"), std::string::npos) + = VString::startsWith(optp, "-fno-") ? (optp + std::strlen("-fno-")) : nullptr) { + if (act.first.substr(std::strlen("-f"), std::string::npos) == nop) { // [-f]opt = [-fno-]opt return act.second.get(); } @@ -139,7 +139,7 @@ V3OptionParser::ActionIfs* V3OptionParser::find(const char* optp) { } if (act.second->isOnOffAllowed()) { // Find starts with "-no" if (const char* const nop - = VString::startsWith(optp, "-no") ? (optp + strlen("-no")) : nullptr) { + = VString::startsWith(optp, "-no") ? (optp + std::strlen("-no")) : nullptr) { if (act.first == nop || act.first == (std::string{"-"} + nop)) { return act.second.get(); } @@ -206,7 +206,7 @@ void V3OptionParser::finalize() { m_pimpl->m_spellCheck.pushCandidate(opt.first); if (opt.second->isFOnOffAllowed()) { m_pimpl->m_spellCheck.pushCandidate( - "-fno-" + opt.first.substr(strlen("-f"), std::string::npos)); + "-fno-" + opt.first.substr(std::strlen("-f"), std::string::npos)); } if (opt.second->isOnOffAllowed()) m_pimpl->m_spellCheck.pushCandidate("-no" + opt.first); } diff --git a/src/V3Options.cpp b/src/V3Options.cpp index d88f6df3c..4456f601e 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -41,7 +41,9 @@ #include #include #include +#include #include +#include #include "config_rev.h" @@ -50,6 +52,8 @@ #endif // clang-format on +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // V3 Internal state @@ -112,7 +116,7 @@ public: V3LangCode::V3LangCode(const char* textp) { // Return code for given string, or ERROR, which is a bad code for (int codei = V3LangCode::L_ERROR; codei < V3LangCode::_ENUM_END; ++codei) { - const V3LangCode code = V3LangCode(codei); + const V3LangCode code{codei}; if (0 == VL_STRCASECMP(textp, code.ascii())) { m_e = code; return; @@ -264,7 +268,7 @@ void VTimescale::parseSlashed(FileLine* fl, const char* textp, VTimescale& unitr if (!precStr.empty()) { VTimescale prec(VTimescale::NONE); bool precbad; - prec = VTimescale(precStr, precbad /*ref*/); + prec = VTimescale{precStr, precbad /*ref*/}; if (precbad) { fl->v3error("`timescale timeprecision syntax error: '" << precStr << "'"); return; @@ -435,6 +439,11 @@ string V3Options::allArgsStringForHierBlock(bool forTop) const { return out; } +void V3Options::ccSet() { // --cc + m_outFormatOk = true; + m_systemC = false; +} + //###################################################################### // File searching @@ -719,9 +728,10 @@ bool V3Options::systemCFound() { // V3 Options notification methods void V3Options::notify() { - FileLine* const cmdfl = new FileLine(FileLine::commandLineFilename()); - // Notify that all arguments have been passed and final modification can be made. + FileLine* const cmdfl = new FileLine{FileLine::commandLineFilename()}; + + if (!outFormatOk() && v3Global.opt.main()) ccSet(); // --main implies --cc if not provided if (!outFormatOk() && !cdc() && !dpiHdrOnly() && !lintOnly() && !preprocOnly() && !xmlOnly()) { v3fatal("verilator: Need --cc, --sc, --cdc, --dpi-hdr-only, --lint-only, " "--xml-only or --E option"); @@ -902,8 +912,8 @@ void V3Options::parseOpts(FileLine* fl, int argc, char** argv) { //====================================================================== bool V3Options::suffixed(const string& sw, const char* arg) { - if (strlen(arg) > sw.length()) return false; - return (0 == strcmp(sw.c_str() + sw.length() - strlen(arg), arg)); + if (std::strlen(arg) > sw.length()) return false; + return (0 == std::strcmp(sw.c_str() + sw.length() - std::strlen(arg), arg)); } void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char** argv) { @@ -998,14 +1008,22 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char m_bboxUnsup = flag; FileLine::globalWarnOff(V3ErrorCode::E_UNSUPPORTED, true); }); - DECL_OPTION("-bin", Set, &m_bin); DECL_OPTION("-build", Set, &m_build); + DECL_OPTION("-build-dep-bin", Set, &m_buildDepBin); + DECL_OPTION("-build-jobs", CbVal, [this, fl](const char* valp) { + int val = std::atoi(valp); + if (val < 0) { + fl->v3fatal("--build-jobs requires a non-negative integer, but '" << valp + << "' was passed"); + val = 1; + } else if (val == 0) { + val = std::thread::hardware_concurrency(); + } + m_buildJobs = val; + }); DECL_OPTION("-CFLAGS", CbVal, callStrSetter(&V3Options::addCFlags)); - DECL_OPTION("-cc", CbCall, [this]() { - m_outFormatOk = true; - m_systemC = false; - }); + DECL_OPTION("-cc", CbCall, [this]() { ccSet(); }); DECL_OPTION("-cdc", OnOff, &m_cdc); DECL_OPTION("-clk", CbVal, callStrSetter(&V3Options::addClocker)); DECL_OPTION("-no-clk", CbVal, callStrSetter(&V3Options::addNoClocker)); @@ -1016,15 +1034,15 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-comp-limit-parens", Set, &m_compLimitParens).undocumented(); DECL_OPTION("-comp-limit-syms", CbVal, [](int val) { VName::maxLength(val); }).undocumented(); DECL_OPTION("-compiler", CbVal, [this, fl](const char* valp) { - if (!strcmp(valp, "clang")) { + if (!std::strcmp(valp, "clang")) { m_compLimitBlocks = 80; // limit unknown m_compLimitMembers = 64; // soft limit, has slowdown bug as of clang++ 3.8 m_compLimitParens = 240; // controlled by -fbracket-depth, which defaults to 256 - } else if (!strcmp(valp, "gcc")) { + } else if (!std::strcmp(valp, "gcc")) { m_compLimitBlocks = 0; // Bug free m_compLimitMembers = 64; // soft limit, has slowdown bug as of g++ 7.1 m_compLimitParens = 240; // Unlimited, but generate same code as for clang - } else if (!strcmp(valp, "msvc")) { + } else if (!std::strcmp(valp, "msvc")) { m_compLimitBlocks = 80; // 128, but allow some room m_compLimitMembers = 0; // probably ok, and AFAIK doesn't support anon structs m_compLimitParens = 80; // 128, but allow some room @@ -1046,7 +1064,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-debug", CbCall, [this]() { setDebugMode(3); }); DECL_OPTION("-debugi", CbVal, [this](int v) { setDebugMode(v); }); DECL_OPTION("-debugi-", CbPartialMatchVal, [this](const char* optp, const char* valp) { - setDebugSrcLevel(optp, std::atoi(valp)); + m_debugLevel[optp] = std::atoi(valp); }); DECL_OPTION("-debug-abort", CbCall, V3Error::vlAbort) @@ -1067,15 +1085,11 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-debug-sigsegv", CbCall, throwSigsegv).undocumented(); // See also --debug-abort DECL_OPTION("-decoration", OnOff, &m_decoration); DECL_OPTION("-dpi-hdr-only", OnOff, &m_dpiHdrOnly); - DECL_OPTION("-dump-defines", OnOff, &m_dumpDefines); - DECL_OPTION("-dump-tree", CbOnOff, - [this](bool flag) { m_dumpTree = flag ? 3 : 0; }); // Also see --dump-treei - DECL_OPTION("-dump-tree-addrids", OnOff, &m_dumpTreeAddrids); - DECL_OPTION("-dump-treei", Set, &m_dumpTree); - DECL_OPTION("-dump-treei-", CbPartialMatchVal, [this](const char* optp, const char* valp) { - setDumpTreeLevel(optp, std::atoi(valp)); + DECL_OPTION("-dump-", CbPartialMatch, [this](const char* optp) { m_dumpLevel[optp] = 3; }); + DECL_OPTION("-no-dump-", CbPartialMatch, [this](const char* optp) { m_dumpLevel[optp] = 0; }); + DECL_OPTION("-dumpi-", CbPartialMatchVal, [this](const char* optp, const char* valp) { + m_dumpLevel[optp] = std::atoi(valp); }); - DECL_OPTION("-E", Set, &m_preprocOnly); DECL_OPTION("-error-limit", CbVal, static_cast(&V3Error::errorLimit)); DECL_OPTION("-exe", OnOff, &m_exe); @@ -1149,7 +1163,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-LDFLAGS", CbVal, callStrSetter(&V3Options::addLdLibs)); const auto setLang = [this, fl](const char* valp) { - const V3LangCode optval = V3LangCode(valp); + const V3LangCode optval{valp}; if (optval.legal()) { m_defaultLanguage = optval; } else { @@ -1175,11 +1189,11 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char m_makeDir = valp; addIncDirFallback(m_makeDir); // Need to find generated files there too }); - DECL_OPTION("-main", OnOff, &m_main).undocumented(); // Future + DECL_OPTION("-main", OnOff, &m_main); DECL_OPTION("-make", CbVal, [this, fl](const char* valp) { - if (!strcmp(valp, "cmake")) { + if (!std::strcmp(valp, "cmake")) { m_cmake = true; - } else if (!strcmp(valp, "gmake")) { + } else if (!std::strcmp(valp, "gmake")) { m_gmake = true; } else { fl->v3fatal("Unknown --make system specified: '" << valp << "'"); @@ -1270,10 +1284,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-pins-uint8", OnOff, &m_pinsUint8); DECL_OPTION("-pipe-filter", Set, &m_pipeFilter); DECL_OPTION("-pp-comments", OnOff, &m_ppComments); - DECL_OPTION("-prefix", CbVal, [this](const char* valp) { - m_prefix = valp; - if (m_modPrefix == "") m_modPrefix = m_prefix; - }); + DECL_OPTION("-prefix", Set, &m_prefix); DECL_OPTION("-private", CbCall, [this]() { m_public = false; }); DECL_OPTION("-prof-c", OnOff, &m_profC); DECL_OPTION("-prof-cfuncs", CbCall, [this]() { m_profC = m_profCFuncs = true; }); @@ -1329,13 +1340,13 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char if (m_threads < 0) fl->v3fatal("--threads must be >= 0: " << valp); }); DECL_OPTION("-threads-dpi", CbVal, [this, fl](const char* valp) { - if (!strcmp(valp, "all")) { + if (!std::strcmp(valp, "all")) { m_threadsDpiPure = true; m_threadsDpiUnpure = true; - } else if (!strcmp(valp, "none")) { + } else if (!std::strcmp(valp, "none")) { m_threadsDpiPure = false; m_threadsDpiUnpure = false; - } else if (!strcmp(valp, "pure")) { + } else if (!std::strcmp(valp, "pure")) { m_threadsDpiPure = true; m_threadsDpiUnpure = false; } else { @@ -1470,13 +1481,13 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-waiver-output", Set, &m_waiverOutput); DECL_OPTION("-x-assign", CbVal, [this, fl](const char* valp) { - if (!strcmp(valp, "0")) { + if (!std::strcmp(valp, "0")) { m_xAssign = "0"; - } else if (!strcmp(valp, "1")) { + } else if (!std::strcmp(valp, "1")) { m_xAssign = "1"; - } else if (!strcmp(valp, "fast")) { + } else if (!std::strcmp(valp, "fast")) { m_xAssign = "fast"; - } else if (!strcmp(valp, "unique")) { + } else if (!std::strcmp(valp, "unique")) { m_xAssign = "unique"; } else { fl->v3fatal("Unknown setting for --x-assign: '" @@ -1485,11 +1496,11 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char } }); DECL_OPTION("-x-initial", CbVal, [this, fl](const char* valp) { - if (!strcmp(valp, "0")) { + if (!std::strcmp(valp, "0")) { m_xInitial = "0"; - } else if (!strcmp(valp, "fast")) { + } else if (!std::strcmp(valp, "fast")) { m_xInitial = "fast"; - } else if (!strcmp(valp, "unique")) { + } else if (!std::strcmp(valp, "unique")) { m_xInitial = "unique"; } else { fl->v3fatal("Unknown setting for --x-initial: '" @@ -1511,16 +1522,22 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char for (int i = 0; i < argc;) { UINFO(9, " Option: " << argv[i] << endl); - if (!strcmp(argv[i], "-j") || !strcmp(argv[i], "--j")) { // Allow gnu -- switches + if (!std::strcmp(argv[i], "-j") + || !std::strcmp(argv[i], "--j")) { // Allow gnu -- switches ++i; - m_buildJobs = 0; // Unlimited parallelism + int val = 0; if (i < argc && isdigit(argv[i][0])) { - m_buildJobs = atoi(argv[i]); - if (m_buildJobs <= 0) { - fl->v3error("-j accepts positive integer, but '" << argv[i] << "' is passed"); + val = atoi(argv[i]); + if (val < 0) { + fl->v3error("-j requires a non-negative integer argument, but '" + << argv[i] << "' was passed"); + val = 1; // Fall-back value, though we will exit on error. + } else if (val == 0) { + val = std::thread::hardware_concurrency(); } ++i; } + if (m_buildJobs == -1) m_buildJobs = val; } else if (argv[i][0] == '-' || argv[i][0] == '+') { const char* argvNoDashp = (argv[i][1] == '-') ? (argv[i] + 2) : (argv[i] + 1); if (const int consumed = parser.parse(i, argc, argv)) { @@ -1552,6 +1569,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char ++i; } } + if (m_buildJobs == -1) m_buildJobs = 1; } //====================================================================== @@ -1739,9 +1757,9 @@ void V3Options::showVersion(bool verbose) { cout << " SYSTEMC_ARCH = " << V3Os::getenvStr("SYSTEMC_ARCH", "") << endl; cout << " SYSTEMC_INCLUDE = " << V3Os::getenvStr("SYSTEMC_INCLUDE", "") << endl; cout << " SYSTEMC_LIBDIR = " << V3Os::getenvStr("SYSTEMC_LIBDIR", "") << endl; - cout << " VERILATOR_ROOT = " << V3Os::getenvStr("VERILATOR_ROOT", "") << endl; - // wrapper uses this: + // wrapper uses VERILATOR_BIN cout << " VERILATOR_BIN = " << V3Os::getenvStr("VERILATOR_BIN", "") << endl; + cout << " VERILATOR_ROOT = " << V3Os::getenvStr("VERILATOR_ROOT", "") << endl; cout << endl; cout << "Features (based on environment or compiled-in support):\n"; @@ -1776,52 +1794,42 @@ V3Options::~V3Options() { VL_DO_CLEAR(delete m_impp, m_impp = nullptr); } void V3Options::setDebugMode(int level) { V3Error::debugDefault(level); - if (!m_dumpTree) m_dumpTree = 3; // Don't override if already set. + if (!m_dumpLevel.count("tree")) m_dumpLevel["tree"] = 3; // Don't override if already set. m_stats = true; m_debugCheck = true; cout << "Starting " << version() << endl; } -void V3Options::setDebugSrcLevel(const string& srcfile, int level) { - const auto iter = m_debugSrcs.find(srcfile); - if (iter != m_debugSrcs.end()) { - iter->second = level; - } else { - m_debugSrcs.emplace(srcfile, level); - } +unsigned V3Options::debugLevel(const string& tag) const { + const auto iter = m_debugLevel.find(tag); + return iter != m_debugLevel.end() ? iter->second : V3Error::debugDefault(); } -int V3Options::debugSrcLevel(const string& srcfile_path, int default_level) { +unsigned V3Options::debugSrcLevel(const string& srcfile_path) const { // For simplicity, calling functions can just use __FILE__ for srcfile. - // That means though we need to cleanup the filename from ../Foo.cpp -> Foo - const string srcfile = V3Os::filenameNonDirExt(srcfile_path); - const auto iter = m_debugSrcs.find(srcfile); - if (iter != m_debugSrcs.end()) { - return iter->second; - } else { - return default_level; - } + // That means we need to strip the filenames: ../Foo.cpp -> Foo + return debugLevel(V3Os::filenameNonDirExt(srcfile_path)); } -void V3Options::setDumpTreeLevel(const string& srcfile, int level) { - const auto iter = m_dumpTrees.find(srcfile); - if (iter != m_dumpTrees.end()) { - iter->second = level; - } else { - m_dumpTrees.emplace(srcfile, level); - } +unsigned V3Options::dumpLevel(const string& tag) const { + const auto iter = m_dumpLevel.find(tag); + return iter != m_dumpLevel.end() ? iter->second : 0; } -int V3Options::dumpTreeLevel(const string& srcfile_path) { +unsigned V3Options::dumpSrcLevel(const string& srcfile_path) const { // For simplicity, calling functions can just use __FILE__ for srcfile. - // That means though we need to cleanup the filename from ../Foo.cpp -> Foo - const string srcfile = V3Os::filenameNonDirExt(srcfile_path); - const auto iter = m_dumpTrees.find(srcfile); - if (iter != m_dumpTrees.end()) { - return iter->second; - } else { - return m_dumpTree; + // That means we need to strip the filenames: ../Foo.cpp -> Foo + return dumpLevel(V3Os::filenameNonDirExt(srcfile_path)); +} + +bool V3Options::dumpTreeAddrids() const { + static int level = -1; + if (VL_UNLIKELY(level < 0)) { + const unsigned value = dumpLevel("tree-addrids"); + if (!available()) return value > 0; + level = static_cast(value); } + return level > 0; } void V3Options::optimize(int level) { diff --git a/src/V3Options.h b/src/V3Options.h index 8637277bb..782987d46 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -39,27 +39,27 @@ class VOptionBool final { public: enum en : uint8_t { OPT_DEFAULT_FALSE = 0, OPT_DEFAULT_TRUE, OPT_TRUE, OPT_FALSE }; enum en m_e; - inline VOptionBool() + VOptionBool() : m_e{OPT_DEFAULT_FALSE} {} // cppcheck-suppress noExplicitConstructor - inline VOptionBool(en _e) + constexpr VOptionBool(en _e) : m_e{_e} {} - explicit inline VOptionBool(int _e) + explicit VOptionBool(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } bool isDefault() const { return m_e == OPT_DEFAULT_FALSE || m_e == OPT_DEFAULT_TRUE; } bool isTrue() const { return m_e == OPT_TRUE || m_e == OPT_DEFAULT_TRUE; } bool isSetTrue() const { return m_e == OPT_TRUE; } bool isSetFalse() const { return m_e == OPT_FALSE; } void setTrueOrFalse(bool flag) { m_e = flag ? OPT_TRUE : OPT_FALSE; } }; -inline bool operator==(const VOptionBool& lhs, const VOptionBool& rhs) { +constexpr bool operator==(const VOptionBool& lhs, const VOptionBool& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VOptionBool& lhs, VOptionBool::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VOptionBool::en lhs, const VOptionBool& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const VOptionBool& lhs, VOptionBool::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(VOptionBool::en lhs, const VOptionBool& rhs) { return lhs == rhs.m_e; } -//###################################################################### +// ###################################################################### class VTimescale final { public: @@ -78,12 +78,12 @@ public: enum : uint8_t { TS_DEFAULT = TS_1PS }; enum en m_e; // CONSTRUCTOR - inline VTimescale() + VTimescale() : m_e{NONE} {} // cppcheck-suppress noExplicitConstructor - inline VTimescale(en _e) + constexpr VTimescale(en _e) : m_e{_e} {} - explicit inline VTimescale(int _e) + explicit VTimescale(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning // Construct from string VTimescale(const string& value, bool& badr); @@ -116,26 +116,30 @@ public: return values[m_e]; } }; -inline bool operator==(const VTimescale& lhs, const VTimescale& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const VTimescale& lhs, VTimescale::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(VTimescale::en lhs, const VTimescale& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const VTimescale& lhs, const VTimescale& rhs) { + return lhs.m_e == rhs.m_e; +} +constexpr bool operator==(const VTimescale& lhs, VTimescale::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(VTimescale::en lhs, const VTimescale& rhs) { return lhs == rhs.m_e; } // Comparisons are based on time, not enum values, so seconds > milliseconds -inline bool operator<(const VTimescale& lhs, const VTimescale& rhs) { return lhs.m_e > rhs.m_e; } +constexpr bool operator<(const VTimescale& lhs, const VTimescale& rhs) { + return lhs.m_e > rhs.m_e; +} inline std::ostream& operator<<(std::ostream& os, const VTimescale& rhs) { return os << rhs.ascii(); } -//###################################################################### +// ###################################################################### class TraceFormat final { public: enum en : uint8_t { VCD = 0, FST } m_e; // cppcheck-suppress noExplicitConstructor - inline TraceFormat(en _e = VCD) + constexpr TraceFormat(en _e = VCD) : m_e{_e} {} - explicit inline TraceFormat(int _e) + explicit TraceFormat(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } bool fst() const { return m_e == FST; } bool vcd() const { return m_e == VCD; } string classBase() const { @@ -147,16 +151,16 @@ public: return names[m_e]; } }; -inline bool operator==(const TraceFormat& lhs, const TraceFormat& rhs) { +constexpr bool operator==(const TraceFormat& lhs, const TraceFormat& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const TraceFormat& lhs, TraceFormat::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(TraceFormat::en lhs, const TraceFormat& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const TraceFormat& lhs, TraceFormat::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(TraceFormat::en lhs, const TraceFormat& rhs) { return lhs == rhs.m_e; } using V3StringList = std::vector; using V3StringSet = std::set; -//###################################################################### +// ###################################################################### // Information given by --hierarchical-block option class V3HierarchicalBlockOption final { @@ -188,7 +192,7 @@ class V3Options final { public: private: // TYPES - using DebugSrcMap = std::map; + using DebugLevelMap = std::map; // MEMBERS (general options) V3OptionsImp* m_impp; // Slow hidden options @@ -206,8 +210,8 @@ private: V3StringSet m_noClockers; // argument: Verilog -noclk signals V3StringList m_vFiles; // argument: Verilog files to read V3StringList m_forceIncs; // argument: -FI - DebugSrcMap m_debugSrcs; // argument: --debugi-= - DebugSrcMap m_dumpTrees; // argument: --dump-treei-= + DebugLevelMap m_debugLevel; // argument: --debugi- + DebugLevelMap m_dumpLevel; // argument: --dumpi- std::map m_parameters; // Parameters std::map m_hierBlocks; // main switch: --hierarchical-block @@ -238,8 +242,6 @@ private: bool m_debugSelfTest = false; // main switch: --debug-self-test bool m_decoration = true; // main switch: --decoration bool m_dpiHdrOnly = false; // main switch: --dpi-hdr-only - bool m_dumpDefines = false; // main switch: --dump-defines - bool m_dumpTreeAddrids = false; // main switch: --dump-tree-addrids bool m_exe = false; // main switch: --exe bool m_flatten = false; // main switch: --flatten bool m_hierarchical = false; // main switch: --hierarchical @@ -283,10 +285,9 @@ private: bool m_xInitialEdge = false; // main switch: --x-initial-edge bool m_xmlOnly = false; // main switch: --xml-only - int m_buildJobs = 1; // main switch: -j + int m_buildJobs = -1; // main switch: --build-jobs, -j int m_convergeLimit = 100; // main switch: --converge-limit int m_coverageMaxWidth = 256; // main switch: --coverage-max-width - int m_dumpTree = 0; // main switch: --dump-tree int m_expandLimit = 64; // main switch: --expand-limit int m_gateStmts = 100; // main switch: --gate-stmts int m_hierChild = 0; // main switch: --hierarchical-child @@ -320,7 +321,7 @@ private: int m_compLimitMembers = 64; // compiler selection; number of members in struct before make anon array int m_compLimitParens = 240; // compiler selection; number of nested parens - string m_bin; // main switch: --bin {binary} + string m_buildDepBin; // main switch: --build-dep-bin {filename} string m_exeName; // main switch: -o {name} string m_flags; // main switch: -f {name} string m_l2Name; // main switch: --l2name; "" for top-module's name @@ -395,10 +396,10 @@ public: V3Options(); ~V3Options(); void setDebugMode(int level); - void setDebugSrcLevel(const string& srcfile, int level); - int debugSrcLevel(const string& srcfile_path, int default_level = V3Error::debugDefault()); - void setDumpTreeLevel(const string& srcfile, int level); - int dumpTreeLevel(const string& srcfile_path); + unsigned debugLevel(const string& tag) const; + unsigned debugSrcLevel(const string& srcfile_path) const; + unsigned dumpLevel(const string& tag) const; + unsigned dumpSrcLevel(const string& srcfile_path) const; // METHODS void addCppFile(const string& filename); @@ -410,15 +411,15 @@ public: void addNoClocker(const string& signame); void addVFile(const string& filename); void addForceInc(const string& filename); - void notify(); bool available() const { return m_available; } + void ccSet(); + void notify(); // ACCESSORS (options) bool preprocOnly() const { return m_preprocOnly; } bool makePhony() const { return m_makePhony; } bool preprocNoLine() const { return m_preprocNoLine; } bool underlineZero() const { return m_underlineZero; } - string bin() const { return m_bin; } string flags() const { return m_flags; } bool systemC() const { return m_systemC; } bool savable() const { return m_savable; } @@ -430,6 +431,8 @@ public: bool bboxSys() const { return m_bboxSys; } bool bboxUnsup() const { return m_bboxUnsup; } bool build() const { return m_build; } + string buildDepBin() const { return m_buildDepBin; } + void buildDepBin(const string& flag) { m_buildDepBin = flag; } bool cdc() const { return m_cdc; } bool cmake() const { return m_cmake; } bool context() const { return m_context; } @@ -450,7 +453,7 @@ public: bool debugSelfTest() const { return m_debugSelfTest; } bool decoration() const { return m_decoration; } bool dpiHdrOnly() const { return m_dpiHdrOnly; } - bool dumpDefines() const { return m_dumpDefines; } + bool dumpDefines() const { return m_dumpLevel.count("defines") && m_dumpLevel.at("defines"); } bool exe() const { return m_exe; } bool flatten() const { return m_flatten; } bool gmake() const { return m_gmake; } @@ -491,8 +494,7 @@ public: int buildJobs() const { return m_buildJobs; } int convergeLimit() const { return m_convergeLimit; } int coverageMaxWidth() const { return m_coverageMaxWidth; } - int dumpTree() const { return m_dumpTree; } - bool dumpTreeAddrids() const { return m_dumpTreeAddrids; } + bool dumpTreeAddrids() const; int expandLimit() const { return m_expandLimit; } int gateStmts() const { return m_gateStmts; } int ifDepth() const { return m_ifDepth; } @@ -630,7 +632,6 @@ public: // Return options for child hierarchical blocks when forTop==false, otherwise returns args for // the top module. string allArgsStringForHierBlock(bool forTop) const; - void bin(const string& flag) { m_bin = flag; } void parseOpts(FileLine* fl, int argc, char** argv); void parseOptsList(FileLine* fl, const string& optdir, int argc, char** argv); void parseOptsFile(FileLine* fl, const string& filename, bool rel); diff --git a/src/V3Order.cpp b/src/V3Order.cpp index 1d83983ea..471012b73 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -107,6 +107,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Utilities @@ -156,8 +158,7 @@ static bool isClockerAssignment(AstNodeAssign* nodep) { bool m_clkAss = false; // There is signals marked as clocker in the assignment private: // METHODS - VL_DEBUG_FUNC; // Declare debug() - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { if (const AstVarRef* const varrefp = VN_CAST(nodep->lhsp(), VarRef)) { if (varrefp->varp()->attrClocker() == VVarAttrClocker::CLOCKER_YES) { m_clkAss = true; @@ -166,8 +167,8 @@ static bool isClockerAssignment(AstNodeAssign* nodep) { } iterateChildren(nodep->rhsp()); } - virtual void visit(AstNodeMath*) override {} // Accelerate - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNode* nodep) override { iterateChildren(nodep); } } visitor; visitor.iterate(nodep); return visitor.m_clkAss; @@ -210,9 +211,8 @@ class OrderClkMarkVisitor final : public VNVisitor { int m_childClkWidth = 0; // If in hasClk, width of clock signal in child // METHODS - VL_DEBUG_FUNC; // Declare debug() - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { m_hasClk = false; m_inAss = true; m_childClkWidth = 0; @@ -236,7 +236,7 @@ class OrderClkMarkVisitor final : public VNVisitor { } } } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { if (m_inAss && nodep->varp()->attrClocker() == VVarAttrClocker::CLOCKER_YES) { if (m_inClocked) { nodep->v3warn(CLKDATA, @@ -249,7 +249,7 @@ class OrderClkMarkVisitor final : public VNVisitor { } } } - virtual void visit(AstConcat* nodep) override { + void visit(AstConcat* nodep) override { if (m_inAss) { iterateAndNextNull(nodep->lhsp()); const int lw = m_childClkWidth; @@ -258,20 +258,20 @@ class OrderClkMarkVisitor final : public VNVisitor { m_childClkWidth = lw + rw; // Pass up } } - virtual void visit(AstNodeSel* nodep) override { + void visit(AstNodeSel* nodep) override { if (m_inAss) { iterateChildren(nodep); // Pass up result width if (m_childClkWidth > nodep->width()) m_childClkWidth = nodep->width(); } } - virtual void visit(AstSel* nodep) override { + void visit(AstSel* nodep) override { if (m_inAss) { iterateChildren(nodep); if (m_childClkWidth > nodep->width()) m_childClkWidth = nodep->width(); } } - virtual void visit(AstReplicate* nodep) override { + void visit(AstReplicate* nodep) override { if (m_inAss) { iterateChildren(nodep); if (VN_IS(nodep->rhsp(), Const)) { @@ -281,12 +281,12 @@ class OrderClkMarkVisitor final : public VNVisitor { } } } - virtual void visit(AstActive* nodep) override { + void visit(AstActive* nodep) override { m_inClocked = nodep->hasClocked(); iterateChildren(nodep); m_inClocked = false; } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } // CONSTRUCTORS explicit OrderClkMarkVisitor(AstNode* nodep) { @@ -295,7 +295,7 @@ class OrderClkMarkVisitor final : public VNVisitor { iterate(nodep); } while (m_newClkMarked); } - virtual ~OrderClkMarkVisitor() override = default; + ~OrderClkMarkVisitor() override = default; public: static void process(AstNetlist* nodep) { OrderClkMarkVisitor{nodep}; } @@ -394,7 +394,6 @@ class OrderBuildVisitor final : public VNVisitor { bool m_inPostponed = false; // Underneath AstAlwaysPostponed // METHODS - VL_DEBUG_FUNC; // Declare debug() void iterateLogic(AstNode* nodep) { UASSERT_OBJ(!m_logicVxp, nodep, "Should not nest"); @@ -416,19 +415,19 @@ class OrderBuildVisitor final : public VNVisitor { } // VISITORS - virtual void visit(AstSenTree* nodep) override { + void visit(AstSenTree* nodep) override { // This should only find the global AstSenTrees under the AstTopScope, which we ignore // here. We visit AstSenTrees separately when encountering the AstActive that references // them. UASSERT_OBJ(!m_scopep, nodep, "AstSenTrees should have been made global in V3ActiveTop"); } - virtual void visit(AstScope* nodep) override { + void visit(AstScope* nodep) override { UASSERT_OBJ(!m_scopep, nodep, "Should not nest"); m_scopep = nodep; iterateChildren(nodep); m_scopep = nullptr; } - virtual void visit(AstActive* nodep) override { + void visit(AstActive* nodep) override { UASSERT_OBJ(!nodep->sensesStorep(), nodep, "AstSenTrees should have been made global in V3ActiveTop"); UASSERT_OBJ(m_scopep, nodep, "AstActive not under AstScope"); @@ -460,7 +459,7 @@ class OrderBuildVisitor final : public VNVisitor { m_activeSenVxp = nullptr; m_domainp = nullptr; } - virtual void visit(AstNodeVarRef* nodep) override { + void visit(AstNodeVarRef* nodep) override { // As we explicitly not visit (see ignored nodes below) any subtree that is not relevant // for ordering, we should be able to assert this: UASSERT_OBJ(m_scopep, nodep, "AstVarRef not under scope"); @@ -635,7 +634,7 @@ class OrderBuildVisitor final : public VNVisitor { } } } - virtual void visit(AstDpiExportUpdated* nodep) override { + void visit(AstDpiExportUpdated* nodep) override { // This is under a logic block (AstAlways) sensitive to a change in the DPI export trigger. // We just need to add an edge to the enclosing logic vertex (the vertex for the // AstAlways). @@ -645,7 +644,7 @@ class OrderBuildVisitor final : public VNVisitor { nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); } - virtual void visit(AstCCall* nodep) override { + void visit(AstCCall* nodep) override { // Calls to 'context' imported DPI function may call DPI exported functions if (m_dpiExportTriggerVxp && nodep->funcp()->dpiImportWrapper() && nodep->funcp()->dpiContext()) { @@ -656,45 +655,45 @@ class OrderBuildVisitor final : public VNVisitor { } //--- Logic akin to SystemVerilog Processes (AstNodeProcedure) - virtual void visit(AstInitial* nodep) override { // + void visit(AstInitial* nodep) override { // iterateLogic(nodep); } - virtual void visit(AstInitialAutomatic* nodep) override { // + void visit(AstInitialAutomatic* nodep) override { // iterateLogic(nodep); } - virtual void visit(AstInitialStatic* nodep) override { // + void visit(AstInitialStatic* nodep) override { // iterateLogic(nodep); } - virtual void visit(AstAlways* nodep) override { // + void visit(AstAlways* nodep) override { // iterateLogic(nodep); } - virtual void visit(AstAlwaysPost* nodep) override { + void visit(AstAlwaysPost* nodep) override { UASSERT_OBJ(!m_inPost, nodep, "Should not nest"); m_inPost = true; iterateLogic(nodep); m_inPost = false; } - virtual void visit(AstAlwaysPostponed* nodep) override { + void visit(AstAlwaysPostponed* nodep) override { UASSERT_OBJ(!m_inPostponed, nodep, "Should not nest"); m_inPostponed = true; iterateLogic(nodep); m_inPostponed = false; } - virtual void visit(AstFinal* nodep) override { // LCOV_EXCL_START + void visit(AstFinal* nodep) override { // LCOV_EXCL_START nodep->v3fatalSrc("AstFinal should have been removed already"); } // LCOV_EXCL_STOP //--- Logic akin go SystemVerilog continuous assignments - virtual void visit(AstAssignAlias* nodep) override { // + void visit(AstAssignAlias* nodep) override { // iterateLogic(nodep); } - virtual void visit(AstAssignW* nodep) override { + void visit(AstAssignW* nodep) override { UASSERT_OBJ(!m_inClkAss, nodep, "Should not nest"); m_inClkAss = isClockerAssignment(nodep); iterateLogic(nodep); m_inClkAss = false; } - virtual void visit(AstAssignPre* nodep) override { + void visit(AstAssignPre* nodep) override { UASSERT_OBJ(!m_inClkAss && !m_inPre, nodep, "Should not nest"); m_inClkAss = isClockerAssignment(nodep); m_inPre = true; @@ -702,7 +701,7 @@ class OrderBuildVisitor final : public VNVisitor { m_inPre = false; m_inClkAss = false; } - virtual void visit(AstAssignPost* nodep) override { + void visit(AstAssignPost* nodep) override { UASSERT_OBJ(!m_inClkAss && !m_inPost, nodep, "Should not nest"); m_inClkAss = isClockerAssignment(nodep); m_inPost = true; @@ -712,21 +711,21 @@ class OrderBuildVisitor final : public VNVisitor { } //--- Verilator concoctions - virtual void visit(AstAlwaysPublic* nodep) override { // + void visit(AstAlwaysPublic* nodep) override { // iterateLogic(nodep); } - virtual void visit(AstCoverToggle* nodep) override { // + void visit(AstCoverToggle* nodep) override { // iterateLogic(nodep); } //--- Ignored nodes - virtual void visit(AstVar*) override {} - virtual void visit(AstVarScope* nodep) override {} - virtual void visit(AstCell*) override {} // Only interested in the respective AstScope - virtual void visit(AstTypeTable*) override {} - virtual void visit(AstConstPool*) override {} - virtual void visit(AstClass*) override {} - virtual void visit(AstCFunc*) override { + void visit(AstVar*) override {} + void visit(AstVarScope* nodep) override {} + void visit(AstCell*) override {} // Only interested in the respective AstScope + void visit(AstTypeTable*) override {} + void visit(AstConstPool*) override {} + void visit(AstClass*) override {} + void visit(AstCFunc*) override { // Calls to DPI exports handled with AstCCall. /* verilator public */ functions are // ignored for now (and hence potentially mis-ordered), but could use the same or // similar mechanism as DPI exports. Every other impure function (including those @@ -734,13 +733,10 @@ class OrderBuildVisitor final : public VNVisitor { } //--- - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } // CONSTRUCTOR explicit OrderBuildVisitor(AstNetlist* nodep) { - // Enable debugging (3 is default if global debug; we want acyc debugging) - if (debug()) m_graphp->debug(5); - // Add edges from the InputVertex to all top level input signal VarStdVertex for (AstVarScope* vscp = nodep->topScopep()->scopep()->varsp(); vscp; vscp = VN_AS(vscp->nextp(), VarScope)) { @@ -816,7 +812,7 @@ public: OrderMoveDomScope::DomScopeMap OrderMoveDomScope::s_dsMap; -inline std::ostream& operator<<(std::ostream& lhs, const OrderMoveDomScope& rhs) { +std::ostream& operator<<(std::ostream& lhs, const OrderMoveDomScope& rhs) { lhs << rhs.name(); return lhs; } @@ -981,15 +977,14 @@ public: : m_pomGraphp{pomGraphp} , m_pomWaitingp{pomWaitingp} {} // METHODS - virtual OrderMoveVertex* makeVertexp(OrderLogicVertex* lvertexp, const OrderEitherVertex*, - const AstScope* scopep, - const AstSenTree* domainp) override { + OrderMoveVertex* makeVertexp(OrderLogicVertex* lvertexp, const OrderEitherVertex*, + const AstScope* scopep, const AstSenTree* domainp) override { OrderMoveVertex* const resultp = new OrderMoveVertex(m_pomGraphp, lvertexp); resultp->domScopep(OrderMoveDomScope::findCreate(domainp, scopep)); resultp->m_pomWaitingE.pushBack(*m_pomWaitingp, resultp); return resultp; } - virtual void freeVertexp(OrderMoveVertex* freeMep) override { + void freeVertexp(OrderMoveVertex* freeMep) override { freeMep->m_pomWaitingE.unlink(*m_pomWaitingp, freeMep); freeMep->unlinkDelete(m_pomGraphp); } @@ -1005,18 +1000,14 @@ class OrderMTaskMoveVertexMaker final public: explicit OrderMTaskMoveVertexMaker(V3Graph* pomGraphp) : m_pomGraphp{pomGraphp} {} - virtual MTaskMoveVertex* makeVertexp(OrderLogicVertex* lvertexp, - const OrderEitherVertex* varVertexp, - const AstScope* scopep, - const AstSenTree* domainp) override { + MTaskMoveVertex* makeVertexp(OrderLogicVertex* lvertexp, const OrderEitherVertex* varVertexp, + const AstScope* scopep, const AstSenTree* domainp) override { // Exclude initial/settle logic from the mtasks graph. // We'll output time-zero logic separately. if (domainp->hasInitial() || domainp->hasSettle()) return nullptr; return new MTaskMoveVertex(m_pomGraphp, lvertexp, varVertexp, scopep, domainp); } - virtual void freeVertexp(MTaskMoveVertex* freeMep) override { - freeMep->unlinkDelete(m_pomGraphp); - } + void freeVertexp(MTaskMoveVertex* freeMep) override { freeMep->unlinkDelete(m_pomGraphp); } private: VL_UNCOPYABLE(OrderMTaskMoveVertexMaker); @@ -1027,8 +1018,8 @@ class OrderVerticesByDomainThenScope final { public: virtual bool operator()(const V3GraphVertex* lhsp, const V3GraphVertex* rhsp) const { - const MTaskMoveVertex* const l_vxp = dynamic_cast(lhsp); - const MTaskMoveVertex* const r_vxp = dynamic_cast(rhsp); + const MTaskMoveVertex* const l_vxp = static_cast(lhsp); + const MTaskMoveVertex* const r_vxp = static_cast(rhsp); uint64_t l_id = m_ids.findId(l_vxp->domainp()); uint64_t r_id = m_ids.findId(r_vxp->domainp()); if (l_id < r_id) return true; @@ -1047,8 +1038,8 @@ public: // Sort vertex's, which must be AbstractMTask's, into a deterministic // order by comparing their serial IDs. virtual bool operator()(const V3GraphVertex* lhsp, const V3GraphVertex* rhsp) const { - const AbstractMTask* const lmtaskp = dynamic_cast(lhsp); - const AbstractMTask* const rmtaskp = dynamic_cast(rhsp); + const AbstractMTask* const lmtaskp = static_cast(lhsp); + const AbstractMTask* const rmtaskp = static_cast(rhsp); return lmtaskp->id() < rmtaskp->id(); } }; @@ -1083,7 +1074,6 @@ class OrderProcess final : VNDeleter { std::array m_statCut; // Count of each edge type cut // METHODS - VL_DEBUG_FUNC; // Declare debug() void process(); void processCircular(); @@ -1335,9 +1325,10 @@ class OrderProcess final : VNDeleter { ~OrderProcess() override { // Stats for (int type = 0; type < OrderVEdgeType::_ENUM_END; type++) { - const double count = double(m_statCut[type]); + const double count{m_statCut[type]}; if (count != 0.0) { - V3Stats::addStat(string("Order, cut, ") + OrderVEdgeType(type).ascii(), count); + V3Stats::addStat(std::string{"Order, cut, "} + OrderVEdgeType{type}.ascii(), + count); } } } @@ -1353,7 +1344,7 @@ public: // OrderMoveDomScope methods // Check the domScope is on ready list, add if not -inline void OrderMoveDomScope::ready(OrderProcess* opp) { +void OrderMoveDomScope::ready(OrderProcess* opp) { if (!m_onReadyList) { m_onReadyList = true; m_readyDomScopeE.pushBack(opp->m_pomReadyDomScope, this); @@ -1361,7 +1352,7 @@ inline void OrderMoveDomScope::ready(OrderProcess* opp) { } // Mark one vertex as finished, remove from ready list if done -inline void OrderMoveDomScope::movedVertex(OrderProcess* opp, OrderMoveVertex* vertexp) { +void OrderMoveDomScope::movedVertex(OrderProcess* opp, OrderMoveVertex* vertexp) { UASSERT_OBJ(m_onReadyList, vertexp, "Moving vertex from ready when nothing was on que as ready."); if (m_readyVertices.empty()) { // Else more work to get to later @@ -1793,7 +1784,7 @@ void OrderProcess::processMoveOne(OrderMoveVertex* vertexp, OrderMoveDomScope* d << " s=" << cvtToHex(scopep) << " " << lvertexp << endl); AstActive* const newActivep = processMoveOneLogic(lvertexp, m_pomNewFuncp /*ref*/, m_pomNewStmts /*ref*/); - if (newActivep) m_scopetop.addActivep(newActivep); + if (newActivep) m_scopetop.addBlocksp(newActivep); processMoveDoneOne(vertexp); } @@ -1815,7 +1806,7 @@ AstActive* OrderProcess::processMoveOneLogic(const OrderLogicVertex* lvertexp, // procedures. Everything else is handled in one go AstNodeProcedure* const procp = VN_CAST(nodep, NodeProcedure); if (procp && !v3Global.opt.profCFuncs()) { - nodep = procp->bodysp(); + nodep = procp->stmtsp(); pushDeletep(procp); } @@ -1835,7 +1826,7 @@ AstActive* OrderProcess::processMoveOneLogic(const OrderLogicVertex* lvertexp, newFuncpr->isLoose(true); newStmtsr = 0; if (domainp->hasInitial() || domainp->hasSettle()) newFuncpr->slow(true); - scopep->addActivep(newFuncpr); + scopep->addBlocksp(newFuncpr); // Create top call to it AstCCall* const callp = new AstCCall(nodep->fileline(), newFuncpr); // Where will we be adding the call? @@ -1890,7 +1881,7 @@ void OrderProcess::processMTasksInitial(InitialLogicE logic_type) { } AstActive* const newActivep = processMoveOneLogic(initp, initCFunc /*ref*/, initStmts /*ref*/); - if (newActivep) m_scopetop.addActivep(newActivep); + if (newActivep) m_scopetop.addBlocksp(newActivep); } } @@ -1932,7 +1923,7 @@ void OrderProcess::processMTasks() { GraphStream emit_logic(&logicGraph); const V3GraphVertex* moveVxp; while ((moveVxp = emit_logic.nextp())) { - const MTaskMoveVertex* const movep = dynamic_cast(moveVxp); + const MTaskMoveVertex* const movep = static_cast(moveVxp); const unsigned mtaskId = movep->color(); UASSERT(mtaskId > 0, "Every MTaskMoveVertex should have an mtask assignment >0"); if (movep->logicp()) { @@ -1970,13 +1961,13 @@ void OrderProcess::processMTasks() { // of the MTask graph. FileLine* const rootFlp = v3Global.rootp()->fileline(); AstExecGraph* const execGraphp = new AstExecGraph{rootFlp, "eval"}; - m_scopetop.addActivep(execGraphp); + m_scopetop.addBlocksp(execGraphp); // Create CFuncs and bodies for each MTask. GraphStream emit_mtasks(&mtasks); const V3GraphVertex* mtaskVxp; while ((mtaskVxp = emit_mtasks.nextp())) { - const AbstractLogicMTask* const mtaskp = dynamic_cast(mtaskVxp); + const AbstractLogicMTask* const mtaskp = static_cast(mtaskVxp); // Create a body for this mtask AstMTaskBody* const bodyp = new AstMTaskBody(rootFlp); @@ -2018,11 +2009,11 @@ void OrderProcess::processMTasks() { for (V3GraphEdge* inp = mtaskp->inBeginp(); inp; inp = inp->inNextp()) { const V3GraphVertex* fromVxp = inp->fromp(); const AbstractLogicMTask* const fromp - = dynamic_cast(fromVxp); + = static_cast(fromVxp); const MTaskState& fromState = mtaskStates[fromp->id()]; new V3GraphEdge(depGraphp, fromState.m_execMTaskp, state.m_execMTaskp, 1); } - execGraphp->addMTaskBodyp(bodyp); + execGraphp->addMTaskBodiesp(bodyp); } } @@ -2031,7 +2022,7 @@ void OrderProcess::processMTasks() { void OrderProcess::process() { // Dump data - m_graph.dumpDotFilePrefixed("orderg_pre"); + if (dumpGraph()) m_graph.dumpDotFilePrefixed("orderg_pre"); // Break cycles. Each strongly connected subgraph (including cutable // edges) will have its own color, and corresponds to a loop in the @@ -2039,12 +2030,12 @@ void OrderProcess::process() { // edges are actually still there, just with weight 0). UINFO(2, " Acyclic & Order...\n"); m_graph.acyclic(&V3GraphEdge::followAlwaysTrue); - m_graph.dumpDotFilePrefixed("orderg_acyc"); + if (dumpGraph()) m_graph.dumpDotFilePrefixed("orderg_acyc"); // Assign ranks so we know what to follow // Then, sort vertices and edges by that ordering m_graph.order(); - m_graph.dumpDotFilePrefixed("orderg_order"); + if (dumpGraph()) m_graph.dumpDotFilePrefixed("orderg_order"); // This finds everything that can be traced from an input (which by // definition are the source clocks). After this any vertex which was @@ -2058,19 +2049,17 @@ void OrderProcess::process() { // Assign logic vertices to new domains UINFO(2, " Domains...\n"); processDomains(); - m_graph.dumpDotFilePrefixed("orderg_domain"); + if (dumpGraph()) m_graph.dumpDotFilePrefixed("orderg_domain"); - if (debug() && v3Global.opt.dumpTree()) processEdgeReport(); + if (dump()) processEdgeReport(); if (!v3Global.opt.mtasks()) { UINFO(2, " Construct Move Graph...\n"); processMoveBuildGraph(); - if (debug() >= 4) { - m_pomGraph.dumpDotFilePrefixed( - "ordermv_start"); // Different prefix (ordermv) as it's not the same graph - } + // Different prefix (ordermv) as it's not the same graph + if (dumpGraph() >= 4) m_pomGraph.dumpDotFilePrefixed("ordermv_start"); m_pomGraph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue); - if (debug() >= 4) m_pomGraph.dumpDotFilePrefixed("ordermv_simpl"); + if (dumpGraph() >= 4) m_pomGraph.dumpDotFilePrefixed("ordermv_simpl"); UINFO(2, " Move...\n"); processMove(); @@ -2084,14 +2073,7 @@ void OrderProcess::process() { processSensitive(); // must be after processDomains // Dump data - m_graph.dumpDotFilePrefixed("orderg_done"); - if (false && debug()) { - const string dfilename - = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "_INT_order"; - const std::unique_ptr logp{V3File::new_ofstream(dfilename)}; - if (logp->fail()) v3fatal("Can't write " << dfilename); - m_graph.dump(*logp); - } + if (dumpGraph()) m_graph.dumpDotFilePrefixed("orderg_done"); } //###################################################################### @@ -2105,8 +2087,6 @@ void V3Order::orderAll(AstNetlist* netlistp) { std::unique_ptr orderGraph = OrderBuildVisitor::process(netlistp); // Order the netlist OrderProcess::main(netlistp, *orderGraph); - // Reset debug level - orderGraph->debug(V3Error::debugDefault()); // Dump tree - V3Global::dumpCheckGlobalTree("order", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("order", 0, dumpTree() >= 3); } diff --git a/src/V3OrderGraph.h b/src/V3OrderGraph.h index 2fb8c33ab..109dfb3cb 100644 --- a/src/V3OrderGraph.h +++ b/src/V3OrderGraph.h @@ -1,6 +1,6 @@ // -*- mode: C++; c-file-style: "cc-mode" -*- //************************************************************************* -// DESCRIPTION: Verilator: Block code ordering +// DESCRIPTION: Verilator: Ordering constraint graph // // Code available from: https://verilator.org // @@ -87,22 +87,22 @@ struct OrderVEdgeType { return names[m_e]; } enum en m_e; - inline OrderVEdgeType() + OrderVEdgeType() : m_e{VERTEX_UNKNOWN} {} // cppcheck-suppress noExplicitConstructor - inline OrderVEdgeType(en _e) + constexpr OrderVEdgeType(en _e) : m_e{_e} {} - explicit inline OrderVEdgeType(int _e) + explicit OrderVEdgeType(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - operator en() const { return m_e; } + constexpr operator en() const { return m_e; } }; -inline bool operator==(const OrderVEdgeType& lhs, const OrderVEdgeType& rhs) { +constexpr bool operator==(const OrderVEdgeType& lhs, const OrderVEdgeType& rhs) { return lhs.m_e == rhs.m_e; } -inline bool operator==(const OrderVEdgeType& lhs, OrderVEdgeType::en rhs) { +constexpr bool operator==(const OrderVEdgeType& lhs, OrderVEdgeType::en rhs) { return lhs.m_e == rhs; } -inline bool operator==(OrderVEdgeType::en lhs, const OrderVEdgeType& rhs) { +constexpr bool operator==(OrderVEdgeType::en lhs, const OrderVEdgeType& rhs) { return lhs == rhs.m_e; } @@ -112,9 +112,9 @@ inline bool operator==(OrderVEdgeType::en lhs, const OrderVEdgeType& rhs) { class OrderGraph final : public V3Graph { public: OrderGraph() = default; - virtual ~OrderGraph() override = default; + ~OrderGraph() override = default; // Methods - virtual void loopsVertexCb(V3GraphVertex* vertexp) override; + void loopsVertexCb(V3GraphVertex* vertexp) override; }; //###################################################################### @@ -136,12 +136,12 @@ public: : V3GraphVertex{graphp} , m_scopep{scopep} , m_domainp{domainp} {} - virtual ~OrderEitherVertex() override = default; - virtual OrderEitherVertex* clone(V3Graph* graphp) const override = 0; + ~OrderEitherVertex() override = default; + OrderEitherVertex* clone(V3Graph* graphp) const override = 0; // Methods virtual OrderVEdgeType type() const = 0; virtual bool domainMatters() = 0; // Must be in same domain when cross edge to this vertex - virtual string dotName() const override { return cvtToHex(m_scopep) + "_"; } + string dotName() const override { return cvtToHex(m_scopep) + "_"; } // ACCESSORS void domainp(AstSenTree* domainp) { m_domainp = domainp; } AstScope* scopep() const { return m_scopep; } @@ -159,16 +159,16 @@ public: : OrderEitherVertex{graphp, nullptr, domainp} { isFromInput(true); // By definition } - virtual ~OrderInputsVertex() override = default; - virtual OrderInputsVertex* clone(V3Graph* graphp) const override { + ~OrderInputsVertex() override = default; + OrderInputsVertex* clone(V3Graph* graphp) const override { return new OrderInputsVertex(graphp, *this); } - virtual OrderVEdgeType type() const override { return OrderVEdgeType::VERTEX_INPUTS; } - virtual string name() const override { return "*INPUTS*"; } - virtual string dotColor() const override { return "green"; } - virtual string dotName() const override { return ""; } - virtual string dotShape() const override { return "invhouse"; } - virtual bool domainMatters() override { return false; } + OrderVEdgeType type() const override { return OrderVEdgeType::VERTEX_INPUTS; } + string name() const override { return "*INPUTS*"; } + string dotColor() const override { return "green"; } + string dotName() const override { return ""; } + string dotShape() const override { return "invhouse"; } + bool domainMatters() override { return false; } }; class OrderLogicVertex final : public OrderEitherVertex { @@ -183,20 +183,18 @@ public: OrderLogicVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* domainp, AstNode* nodep) : OrderEitherVertex{graphp, scopep, domainp} , m_nodep{nodep} {} - virtual ~OrderLogicVertex() override = default; - virtual OrderLogicVertex* clone(V3Graph* graphp) const override { + ~OrderLogicVertex() override = default; + OrderLogicVertex* clone(V3Graph* graphp) const override { return new OrderLogicVertex(graphp, *this); } - virtual OrderVEdgeType type() const override { return OrderVEdgeType::VERTEX_LOGIC; } - virtual bool domainMatters() override { return true; } + OrderVEdgeType type() const override { return OrderVEdgeType::VERTEX_LOGIC; } + bool domainMatters() override { return true; } // ACCESSORS - virtual string name() const override { + string name() const override { return (cvtToHex(m_nodep) + "\\n " + cvtToStr(nodep()->typeName())); } AstNode* nodep() const { return m_nodep; } - virtual string dotShape() const override { - return VN_IS(m_nodep, Active) ? "doubleoctagon" : "rect"; - } + string dotShape() const override { return VN_IS(m_nodep, Active) ? "doubleoctagon" : "rect"; } }; class OrderVarVertex VL_NOT_FINAL : public OrderEitherVertex { @@ -214,17 +212,17 @@ public: OrderVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) : OrderEitherVertex{graphp, scopep, nullptr} , m_varScp{varScp} {} - virtual ~OrderVarVertex() override = default; - virtual OrderVarVertex* clone(V3Graph* graphp) const override = 0; - virtual OrderVEdgeType type() const override = 0; - virtual FileLine* fileline() const override { return varScp()->fileline(); } + ~OrderVarVertex() override = default; + OrderVarVertex* clone(V3Graph* graphp) const override = 0; + OrderVEdgeType type() const override = 0; + FileLine* fileline() const override { return varScp()->fileline(); } // ACCESSORS AstVarScope* varScp() const { return m_varScp; } void isClock(bool flag) { m_isClock = flag; } bool isClock() const { return m_isClock; } void isDelayed(bool flag) { m_isDelayed = flag; } bool isDelayed() const { return m_isDelayed; } - virtual string dotShape() const override { return "ellipse"; } + string dotShape() const override { return "ellipse"; } }; class OrderVarStdVertex final : public OrderVarVertex { @@ -234,16 +232,14 @@ class OrderVarStdVertex final : public OrderVarVertex { public: OrderVarStdVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) : OrderVarVertex{graphp, scopep, varScp} {} - virtual ~OrderVarStdVertex() override = default; - virtual OrderVarStdVertex* clone(V3Graph* graphp) const override { + ~OrderVarStdVertex() override = default; + OrderVarStdVertex* clone(V3Graph* graphp) const override { return new OrderVarStdVertex(graphp, *this); } - virtual OrderVEdgeType type() const override { return OrderVEdgeType::VERTEX_VARSTD; } - virtual string name() const override { - return (cvtToHex(varScp()) + "\\n " + varScp()->name()); - } - virtual string dotColor() const override { return "grey"; } - virtual bool domainMatters() override { return true; } + OrderVEdgeType type() const override { return OrderVEdgeType::VERTEX_VARSTD; } + string name() const override { return (cvtToHex(varScp()) + "\\n " + varScp()->name()); } + string dotColor() const override { return "grey"; } + bool domainMatters() override { return true; } }; class OrderVarPreVertex final : public OrderVarVertex { OrderVarPreVertex(V3Graph* graphp, const OrderVarPreVertex& old) @@ -252,16 +248,14 @@ class OrderVarPreVertex final : public OrderVarVertex { public: OrderVarPreVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) : OrderVarVertex{graphp, scopep, varScp} {} - virtual ~OrderVarPreVertex() override = default; - virtual OrderVarPreVertex* clone(V3Graph* graphp) const override { + ~OrderVarPreVertex() override = default; + OrderVarPreVertex* clone(V3Graph* graphp) const override { return new OrderVarPreVertex(graphp, *this); } - virtual OrderVEdgeType type() const override { return OrderVEdgeType::VERTEX_VARPRE; } - virtual string name() const override { - return (cvtToHex(varScp()) + " PRE\\n " + varScp()->name()); - } - virtual string dotColor() const override { return "green"; } - virtual bool domainMatters() override { return false; } + OrderVEdgeType type() const override { return OrderVEdgeType::VERTEX_VARPRE; } + string name() const override { return (cvtToHex(varScp()) + " PRE\\n " + varScp()->name()); } + string dotColor() const override { return "green"; } + bool domainMatters() override { return false; } }; class OrderVarPostVertex final : public OrderVarVertex { OrderVarPostVertex(V3Graph* graphp, const OrderVarPostVertex& old) @@ -270,16 +264,14 @@ class OrderVarPostVertex final : public OrderVarVertex { public: OrderVarPostVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) : OrderVarVertex{graphp, scopep, varScp} {} - virtual OrderVarPostVertex* clone(V3Graph* graphp) const override { + OrderVarPostVertex* clone(V3Graph* graphp) const override { return new OrderVarPostVertex(graphp, *this); } - virtual OrderVEdgeType type() const override { return OrderVEdgeType::VERTEX_VARPOST; } - virtual ~OrderVarPostVertex() override = default; - virtual string name() const override { - return (cvtToHex(varScp()) + " POST\\n " + varScp()->name()); - } - virtual string dotColor() const override { return "red"; } - virtual bool domainMatters() override { return false; } + OrderVEdgeType type() const override { return OrderVEdgeType::VERTEX_VARPOST; } + ~OrderVarPostVertex() override = default; + string name() const override { return (cvtToHex(varScp()) + " POST\\n " + varScp()->name()); } + string dotColor() const override { return "red"; } + bool domainMatters() override { return false; } }; class OrderVarPordVertex final : public OrderVarVertex { OrderVarPordVertex(V3Graph* graphp, const OrderVarPordVertex& old) @@ -288,16 +280,14 @@ class OrderVarPordVertex final : public OrderVarVertex { public: OrderVarPordVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) : OrderVarVertex{graphp, scopep, varScp} {} - virtual ~OrderVarPordVertex() override = default; - virtual OrderVarPordVertex* clone(V3Graph* graphp) const override { + ~OrderVarPordVertex() override = default; + OrderVarPordVertex* clone(V3Graph* graphp) const override { return new OrderVarPordVertex(graphp, *this); } - virtual OrderVEdgeType type() const override { return OrderVEdgeType::VERTEX_VARPORD; } - virtual string name() const override { - return (cvtToHex(varScp()) + " PORD\\n " + varScp()->name()); - } - virtual string dotColor() const override { return "blue"; } - virtual bool domainMatters() override { return false; } + OrderVEdgeType type() const override { return OrderVEdgeType::VERTEX_VARPORD; } + string name() const override { return (cvtToHex(varScp()) + " PORD\\n " + varScp()->name()); } + string dotColor() const override { return "blue"; } + bool domainMatters() override { return false; } }; //###################################################################### @@ -324,28 +314,28 @@ public: , m_logicp{logicp} , m_state{POM_WAIT} , m_domScopep{nullptr} {} - virtual ~OrderMoveVertex() override = default; - virtual OrderMoveVertex* clone(V3Graph* graphp) const override { + ~OrderMoveVertex() override = default; + OrderMoveVertex* clone(V3Graph* graphp) const override { v3fatalSrc("Unsupported"); return nullptr; } // METHODS virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_MOVE; } - virtual string dotColor() const override { + string dotColor() const override { if (logicp()) { return logicp()->dotColor(); } else { return ""; } } - virtual FileLine* fileline() const override { + FileLine* fileline() const override { if (logicp()) { return logicp()->fileline(); } else { return nullptr; } } - virtual string name() const override { + string name() const override { string nm; if (VL_UNCOVERABLE(!logicp())) { // Avoid crash when debugging nm = "nul"; // LCOV_EXCL_LINE @@ -394,20 +384,20 @@ public: , m_domainp{domainp} { UASSERT(!(logicp && varp), "MTaskMoveVertex: logicp and varp may not both be set!\n"); } - virtual ~MTaskMoveVertex() override = default; - virtual MTaskMoveVertex* clone(V3Graph* graphp) const override { + ~MTaskMoveVertex() override = default; + MTaskMoveVertex* clone(V3Graph* graphp) const override { v3fatalSrc("Unsupported"); return nullptr; } virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_MOVE; } - virtual string dotColor() const override { + string dotColor() const override { if (logicp()) { return logicp()->dotColor(); } else { return "yellow"; } } - virtual string name() const override { + string name() const override { string nm; if (logicp()) { nm = logicp()->name(); @@ -439,10 +429,9 @@ public: OrderEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, bool cutable = false) : V3GraphEdge{graphp, fromp, top, weight, cutable} {} - virtual ~OrderEdge() override = default; + ~OrderEdge() override = default; virtual OrderVEdgeType type() const { return OrderVEdgeType::EDGE_STD; } - virtual OrderEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, - V3GraphVertex* top) const override { + OrderEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const override { return new OrderEdge(graphp, fromp, top, *this); } // When ordering combo blocks with stronglyConnected, follow edges not @@ -466,14 +455,14 @@ class OrderComboCutEdge final : public OrderEdge { public: OrderComboCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) : OrderEdge{graphp, fromp, top, WEIGHT_COMBO, CUTABLE} {} - virtual OrderVEdgeType type() const override { return OrderVEdgeType::EDGE_COMBOCUT; } - virtual ~OrderComboCutEdge() override = default; - virtual OrderComboCutEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, - V3GraphVertex* top) const override { + OrderVEdgeType type() const override { return OrderVEdgeType::EDGE_COMBOCUT; } + ~OrderComboCutEdge() override = default; + OrderComboCutEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, + V3GraphVertex* top) const override { return new OrderComboCutEdge(graphp, fromp, top, *this); } - virtual string dotColor() const override { return "yellowGreen"; } - virtual bool followComboConnected() const override { return true; } + string dotColor() const override { return "yellowGreen"; } + bool followComboConnected() const override { return true; } }; class OrderPostCutEdge final : public OrderEdge { @@ -487,14 +476,14 @@ class OrderPostCutEdge final : public OrderEdge { public: OrderPostCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) : OrderEdge{graphp, fromp, top, WEIGHT_COMBO, CUTABLE} {} - virtual OrderVEdgeType type() const override { return OrderVEdgeType::EDGE_POSTCUT; } - virtual ~OrderPostCutEdge() override = default; - virtual OrderPostCutEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, - V3GraphVertex* top) const override { + OrderVEdgeType type() const override { return OrderVEdgeType::EDGE_POSTCUT; } + ~OrderPostCutEdge() override = default; + OrderPostCutEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, + V3GraphVertex* top) const override { return new OrderPostCutEdge(graphp, fromp, top, *this); } - virtual string dotColor() const override { return "PaleGreen"; } - virtual bool followComboConnected() const override { return false; } + string dotColor() const override { return "PaleGreen"; } + bool followComboConnected() const override { return false; } }; class OrderPreCutEdge final : public OrderEdge { @@ -508,14 +497,14 @@ class OrderPreCutEdge final : public OrderEdge { public: OrderPreCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) : OrderEdge{graphp, fromp, top, WEIGHT_PRE, CUTABLE} {} - virtual OrderVEdgeType type() const override { return OrderVEdgeType::EDGE_PRECUT; } - virtual OrderPreCutEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, - V3GraphVertex* top) const override { + OrderVEdgeType type() const override { return OrderVEdgeType::EDGE_PRECUT; } + OrderPreCutEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, + V3GraphVertex* top) const override { return new OrderPreCutEdge(graphp, fromp, top, *this); } - virtual ~OrderPreCutEdge() override = default; - virtual string dotColor() const override { return "khaki"; } - virtual bool followComboConnected() const override { return false; } + ~OrderPreCutEdge() override = default; + string dotColor() const override { return "khaki"; } + bool followComboConnected() const override { return false; } }; #endif // Guard diff --git a/src/V3Os.cpp b/src/V3Os.cpp index c410c6735..32d78f09c 100644 --- a/src/V3Os.cpp +++ b/src/V3Os.cpp @@ -29,8 +29,13 @@ #include "verilatedos.h" // Limited V3 headers here - this is a base class for Vlc etc -#include "V3String.h" #include "V3Os.h" +#include "V3String.h" + +#ifndef V3ERROR_NO_GLOBAL_ +#include "V3Global.h" +VL_DEFINE_DEBUG_FUNCTIONS; +#endif #include #include // PATH_MAX (especially on FreeBSD) @@ -38,6 +43,7 @@ #include #include #include + #include #include @@ -347,7 +353,7 @@ int V3Os::system(const string& command) { const int ret = ::system(command.c_str()); if (VL_UNCOVERABLE(ret == -1)) { v3fatal("Failed to execute command:" // LCOV_EXCL_LINE - << command << " " << strerror(errno)); + << command << " " << std::strerror(errno)); return -1; // LCOV_EXCL_LINE } else { UASSERT(WIFEXITED(ret), "system(" << command << ") returned unexpected value of " << ret); diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 01807114f..18dfc06b6 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -65,6 +65,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Hierarchical block and parameter db (modules without parameter is also handled) @@ -88,7 +90,6 @@ class ParameterizedHierBlocks final { m_modParams; // Parameter variables of hierarchical blocks // METHODS - VL_DEBUG_FUNC; // Declare debug() public: ParameterizedHierBlocks(const V3HierBlockOptSet& hierOpts, AstNetlist* nodep) { @@ -100,7 +101,7 @@ public: for (V3HierarchicalBlockOption::ParamStrMap::const_iterator pIt = params.begin(); pIt != params.end(); ++pIt) { std::unique_ptr constp{AstConst::parseParamLiteral( - new FileLine(FileLine::EmptySecret()), pIt->second)}; + new FileLine{FileLine::builtInFilename()}, pIt->second)}; UASSERT(constp, pIt->second << " is not a valid parameter literal"); const bool inserted = consts.emplace(pIt->first, std::move(constp)).second; UASSERT(inserted, pIt->first << " is already added"); @@ -270,7 +271,6 @@ class ParamProcessor final { std::map m_defaultParameterValues; // METHODS - VL_DEBUG_FUNC; // Declare debug() static void makeSmallNames(AstNodeModule* modp) { std::vector usedLetter; @@ -888,7 +888,6 @@ class ParamVisitor final : public VNVisitor { std::unordered_map> m_parentps; // METHODS - VL_DEBUG_FUNC; // Declare debug() void visitCells(AstNodeModule* nodep) { UASSERT_OBJ(!m_iterateModule, nodep, "Should not nest"); @@ -977,7 +976,7 @@ class ParamVisitor final : public VNVisitor { } // VISITORS - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { if (nodep->recursiveClone()) nodep->dead(true); // Fake, made for recursive elimination if (nodep->dead()) return; // Marked by LinkDot (and above) @@ -995,14 +994,14 @@ class ParamVisitor final : public VNVisitor { } } - virtual void visit(AstCell* nodep) override { + void visit(AstCell* nodep) override { visitCellOrClassRef(nodep, VN_IS(nodep->modp(), Iface)); } - virtual void visit(AstClassRefDType* nodep) override { visitCellOrClassRef(nodep, false); } - virtual void visit(AstClassOrPackageRef* nodep) override { visitCellOrClassRef(nodep, false); } + void visit(AstClassRefDType* nodep) override { visitCellOrClassRef(nodep, false); } + void visit(AstClassOrPackageRef* nodep) override { visitCellOrClassRef(nodep, false); } // Make sure all parameters are constantified - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { if (nodep->user5SetOnce()) return; // Process once iterateChildren(nodep); if (nodep->isParam()) { @@ -1015,7 +1014,7 @@ class ParamVisitor final : public VNVisitor { } } // Make sure varrefs cause vars to constify before things above - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { // Might jump across functions, so beware if ever add a m_funcp if (nodep->varp()) iterate(nodep->varp()); } @@ -1036,7 +1035,7 @@ class ParamVisitor final : public VNVisitor { } return false; } - virtual void visit(AstVarXRef* nodep) override { + void visit(AstVarXRef* nodep) override { // Check to see if the scope is just an interface because interfaces are special const string dotted = nodep->dotted(); if (!dotted.empty() && nodep->varp() && nodep->varp()->isParam()) { @@ -1082,7 +1081,7 @@ class ParamVisitor final : public VNVisitor { nodep->varp(nullptr); // Needs relink, as may remove pointed-to var } - virtual void visit(AstUnlinkedRef* nodep) override { + void visit(AstUnlinkedRef* nodep) override { AstVarXRef* const varxrefp = VN_CAST(nodep->op1p(), VarXRef); AstNodeFTaskRef* const taskrefp = VN_CAST(nodep->op1p(), NodeFTaskRef); if (varxrefp) { @@ -1103,7 +1102,7 @@ class ParamVisitor final : public VNVisitor { nodep->replaceWith(nodep->op1p()->unlinkFrBack()); VL_DO_DANGLING(pushDeletep(nodep), nodep); } - virtual void visit(AstCellArrayRef* nodep) override { + void visit(AstCellArrayRef* nodep) override { V3Const::constifyParamsEdit(nodep->selp()); if (const AstConst* const constp = VN_CAST(nodep->selp(), Const)) { const string index = AstNode::encodeNumber(constp->toSInt()); @@ -1122,7 +1121,7 @@ class ParamVisitor final : public VNVisitor { } // Generate Statements - virtual void visit(AstGenIf* nodep) override { + void visit(AstGenIf* nodep) override { UINFO(9, " GENIF " << nodep << endl); iterateAndNextNull(nodep->condp()); // We suppress errors when widthing params since short-circuiting in @@ -1132,7 +1131,7 @@ class ParamVisitor final : public VNVisitor { // NOT recurse the body. V3Const::constifyGenerateParamsEdit(nodep->condp()); // condp may change if (const AstConst* const constp = VN_CAST(nodep->condp(), Const)) { - if (AstNode* const keepp = (constp->isZero() ? nodep->elsesp() : nodep->ifsp())) { + if (AstNode* const keepp = (constp->isZero() ? nodep->elsesp() : nodep->thensp())) { keepp->unlinkFrBackWithNext(); nodep->replaceWith(keepp); } else { @@ -1149,10 +1148,8 @@ class ParamVisitor final : public VNVisitor { //! @todo Unlike generated IF, we don't have to worry about short-circuiting the conditional //! expression, since this is currently restricted to simple comparisons. If we ever do //! move to more generic constant expressions, such code will be needed here. - virtual void visit(AstBegin* nodep) override { - if (nodep->genforp()) { - AstGenFor* const forp = VN_AS(nodep->genforp(), GenFor); - UASSERT_OBJ(forp, nodep, "Non-GENFOR under generate-for BEGIN"); + void visit(AstBegin* nodep) override { + if (AstGenFor* const forp = VN_AS(nodep->genforp(), GenFor)) { // We should have a GENFOR under here. We will be replacing the begin, // so process here rather than at the generate to avoid iteration problems UINFO(9, " BEGIN " << nodep << endl); @@ -1181,10 +1178,10 @@ class ParamVisitor final : public VNVisitor { iterateChildren(nodep); } } - virtual void visit(AstGenFor* nodep) override { // LCOV_EXCL_LINE + void visit(AstGenFor* nodep) override { // LCOV_EXCL_LINE nodep->v3fatalSrc("GENFOR should have been wrapped in BEGIN"); } - virtual void visit(AstGenCase* nodep) override { + void visit(AstGenCase* nodep) override { UINFO(9, " GENCASE " << nodep << endl); AstNode* keepp = nullptr; iterateAndNextNull(nodep->exprp()); @@ -1211,7 +1208,7 @@ class ParamVisitor final : public VNVisitor { if (const AstConst* const ccondp = VN_CAST(ep, Const)) { V3Number match(nodep, 1); match.opEq(ccondp->num(), exprp->num()); - if (!keepp && match.isNeqZero()) keepp = itemp->bodysp(); + if (!keepp && match.isNeqZero()) keepp = itemp->stmtsp(); } else { itemp->v3error("Generate Case item does not evaluate to constant"); } @@ -1222,7 +1219,7 @@ class ParamVisitor final : public VNVisitor { for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp = VN_AS(itemp->nextp(), CaseItem)) { if (itemp->isDefault()) { - if (!keepp) keepp = itemp->bodysp(); + if (!keepp) keepp = itemp->stmtsp(); } } // Replace @@ -1235,7 +1232,7 @@ class ParamVisitor final : public VNVisitor { VL_DO_DANGLING(nodep->deleteTree(), nodep); } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -1269,10 +1266,10 @@ public: }); // Re-insert modules - for (AstNodeModule* const modp : modps) netlistp->addModulep(modp); + for (AstNodeModule* const modp : modps) netlistp->addModulesp(modp); } } - virtual ~ParamVisitor() override = default; + ~ParamVisitor() override = default; VL_UNCOPYABLE(ParamVisitor); }; @@ -1282,5 +1279,5 @@ public: void V3Param::param(AstNetlist* rootp) { UINFO(2, __FUNCTION__ << ": " << endl); { ParamVisitor{rootp}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("param", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6); + V3Global::dumpCheckGlobalTree("param", 0, dumpTree() >= 6); } diff --git a/src/V3ParseGrammar.cpp b/src/V3ParseGrammar.cpp index 38bae0374..984544d82 100644 --- a/src/V3ParseGrammar.cpp +++ b/src/V3ParseGrammar.cpp @@ -18,6 +18,8 @@ #include "V3Ast.h" // This must be before V3ParseBison.cpp, as we don't want #defines to conflict +VL_DEFINE_DEBUG_FUNCTIONS; + //====================================================================== // The guts come from bison output @@ -67,16 +69,15 @@ void V3ParseImp::parserClear() { //====================================================================== // V3ParseGrammar functions requiring bison state -AstNode* V3ParseGrammar::argWrapList(AstNode* nodep) { +AstArg* V3ParseGrammar::argWrapList(AstNode* nodep) { // Convert list of expressions to list of arguments if (!nodep) return nullptr; - AstNode* outp = nullptr; + AstArg* outp = nullptr; AstBegin* const tempp = new AstBegin(nodep->fileline(), "[EditWrapper]", nodep); while (nodep) { AstNode* const nextp = nodep->nextp(); AstNode* const exprp = nodep->unlinkFrBack(); nodep = nextp; - // addNext can handle nulls: outp = AstNode::addNext(outp, new AstArg(exprp->fileline(), "", exprp)); } VL_DO_DANGLING(tempp->deleteTree(), tempp); @@ -84,9 +85,13 @@ AstNode* V3ParseGrammar::argWrapList(AstNode* nodep) { } AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, const string& name, int value) { - return new AstAssignW( - fileline, new AstVarRef(fileline, name, VAccess::WRITE), - new AstConst(fileline, AstConst::StringToParse(), (value ? "'1" : "'0"))); + AstAssignW* assignp + = new AstAssignW{fileline, new AstVarRef{fileline, name, VAccess::WRITE}, + new AstConst{fileline, AstConst::StringToParse{}, (value ? "'1" : "'0")}}; + AstStrengthSpec* strengthSpecp + = new AstStrengthSpec{fileline, VStrength::SUPPLY, VStrength::SUPPLY}; + assignp->strengthSpecp(strengthSpecp); + return assignp; } AstRange* V3ParseGrammar::scrubRange(AstNodeRange* nrangep) { @@ -200,15 +205,17 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name, } if (GRAMMARP->m_varDecl == VVarType::SUPPLY0) { - nodep->addNext(V3ParseGrammar::createSupplyExpr(fileline, nodep->name(), 0)); + AstNode::addNext( + nodep, V3ParseGrammar::createSupplyExpr(fileline, nodep->name(), 0)); } if (GRAMMARP->m_varDecl == VVarType::SUPPLY1) { - nodep->addNext(V3ParseGrammar::createSupplyExpr(fileline, nodep->name(), 1)); + AstNode::addNext( + nodep, V3ParseGrammar::createSupplyExpr(fileline, nodep->name(), 1)); } if (VN_IS(dtypep, ParseTypeDType)) { // Parser needs to know what is a type AstNode* const newp = new AstTypedefFwd(fileline, name); - nodep->addNext(newp); + AstNode::addNext(nodep, newp); SYMP->reinsert(newp); } // Don't set dtypep in the ranging; diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index 924a5062b..cb26c7026 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -38,6 +38,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //====================================================================== // Globals @@ -58,7 +60,7 @@ V3ParseImp::~V3ParseImp() { if (debug() >= 9) { UINFO(0, "~V3ParseImp\n"); - symp()->dump(cout, "-vpi: "); + symp()->dumpSelf(cout, "-vpi: "); } } @@ -89,19 +91,19 @@ void V3ParseImp::lexTimescaleParse(FileLine* fl, const char* textp) { } void V3ParseImp::timescaleMod(FileLine* fl, AstNodeModule* modp, bool unitSet, double unitVal, bool precSet, double precVal) { - VTimescale unit(VTimescale::NONE); + VTimescale unit{VTimescale::NONE}; if (unitSet) { bool bad; - unit = VTimescale(unitVal, bad /*ref*/); + unit = VTimescale{unitVal, bad /*ref*/}; if (bad) { UINFO(1, "Value = " << unitVal << endl); fl->v3error("timeunit illegal value"); } } - VTimescale prec(VTimescale::NONE); + VTimescale prec{VTimescale::NONE}; if (precSet) { bool bad; - prec = VTimescale(precVal, bad /*ref*/); + prec = VTimescale{precVal, bad /*ref*/}; if (bad) { UINFO(1, "Value = " << precVal << endl); fl->v3error("timeprecision illegal value"); @@ -150,8 +152,8 @@ void V3ParseImp::lexVerilatorCmtLint(FileLine* fl, const char* textp, bool warnO void V3ParseImp::lexVerilatorCmtBad(FileLine* fl, const char* textp) { string cmtparse = textp; - if (cmtparse.substr(0, strlen("/*verilator")) == "/*verilator") { - cmtparse.replace(0, strlen("/*verilator"), ""); + if (cmtparse.substr(0, std::strlen("/*verilator")) == "/*verilator") { + cmtparse.replace(0, std::strlen("/*verilator"), ""); } while (isspace(cmtparse[0])) cmtparse.replace(0, 1, ""); string cmtname; @@ -178,14 +180,14 @@ void V3ParseImp::lexErrorPreprocDirective(FileLine* fl, const char* textp) { } string V3ParseImp::lexParseTag(const char* textp) { - string tmp = textp + strlen("/*verilator tag "); + string tmp = textp + std::strlen("/*verilator tag "); string::size_type pos; if ((pos = tmp.rfind("*/")) != string::npos) tmp.erase(pos); return tmp; } double V3ParseImp::lexParseTimenum(const char* textp) { - const size_t length = strlen(textp); + const size_t length = std::strlen(textp); char* const strgp = new char[length + 1]; char* dp = strgp; const char* sp = textp; @@ -234,7 +236,7 @@ size_t V3ParseImp::ppInputToLex(char* buf, size_t max_size) { m_ppBuffers.push_front(remainder); // Put back remainder for next time len = (max_size - got); } - memcpy(buf + got, front.c_str(), len); + std::memcpy(buf + got, front.c_str(), len); got += len; } if (debug() >= 9) { @@ -283,7 +285,7 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i if (errmsg != "") return; // Threw error already // Create fake node for later error reporting AstNodeModule* const nodep = new AstNotFoundModule(fileline, modname); - v3Global.rootp()->addModulep(nodep); + v3Global.rootp()->addModulesp(nodep); return; } @@ -398,8 +400,7 @@ void V3ParseImp::tokenPipeline() { const int nexttok = nexttokp->token; yylval = curValue; // Now potentially munge the current token - if (token == '(' - && (nexttok == ygenSTRENGTH || nexttok == ySUPPLY0 || nexttok == ySUPPLY1)) { + if (token == '(' && isStrengthToken(nexttok)) { token = yP_PAR__STRENGTH; } else if (token == ':') { if (nexttok == yBEGIN) { @@ -483,6 +484,12 @@ void V3ParseImp::tokenPipeline() { // effectively returns yylval } +bool V3ParseImp::isStrengthToken(int tok) { + return tok == ygenSTRENGTH || tok == ySUPPLY0 || tok == ySUPPLY1 || tok == ySTRONG0 + || tok == ySTRONG1 || tok == yPULL0 || tok == yPULL1 || tok == yWEAK0 || tok == yWEAK1 + || tok == yHIGHZ0 || tok == yHIGHZ1; +} + void V3ParseImp::tokenPipelineSym() { // If an id, change the type based on symbol table // Note above sometimes converts yGLOBAL to a yaID__LEX @@ -492,7 +499,7 @@ void V3ParseImp::tokenPipelineSym() { const VSymEnt* foundp; if (const VSymEnt* const look_underp = V3ParseImp::parsep()->symp()->nextId()) { UINFO(7, " tokenPipelineSym: next id lookup forced under " << look_underp << endl); - // if (debug() >= 7) V3ParseImp::parsep()->symp()->dump(cout, " -symtree: "); + // if (debug() >= 7) V3ParseImp::parsep()->symp()->dumpSelf(cout, " -symtree: "); foundp = look_underp->findIdFallback(*(yylval.strp)); // "consume" it. Must set again if want another token under temp scope V3ParseImp::parsep()->symp()->nextId(nullptr); @@ -500,7 +507,7 @@ void V3ParseImp::tokenPipelineSym() { UINFO(7, " tokenPipelineSym: find upward " << V3ParseImp::parsep()->symp()->symCurrentp() << " for '" << *(yylval.strp) << "'" << endl); - // if (debug()>=9) V3ParseImp::parsep()->symp()->symCurrentp()->dump(cout, + // if (debug()>=9) V3ParseImp::parsep()->symp()->symCurrentp()->dumpSelf(cout, // " -findtree: ", true); foundp = V3ParseImp::parsep()->symp()->symCurrentp()->findIdFallback(*(yylval.strp)); } diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index c5cf4bd36..54c4ab080 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -121,6 +121,7 @@ struct V3ParseBisonYYSType { V3ErrorCode::en errcodeen; VAttrType::en attrtypeen; VLifetime::en lifetime; + VStrength::en strength; #include "V3Ast__gen_yystype.h" }; @@ -160,25 +161,10 @@ class V3ParseImp final { VTimescale m_timeLastUnit; // Last `timescale's unit public: + VL_DEFINE_DEBUG_FUNCTIONS; // Note these are an exception to using the filename as the debug type - static int debugBison() { - static int level = -1; - if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel("bison"); - return level; - } - static int debugFlex() { - static int level = -1; - if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel("flex"); - return level; - } - static int debug() { - static int level = -1; - if (VL_UNLIKELY(level < 0)) { - level = std::max(std::max(debugBison(), debugFlex()), - v3Global.opt.debugSrcLevel("V3ParseImp")); - } - return level; - } + VL_DEFINE_DEBUG(Bison); // Define 'unsigned debugBison()' + VL_DEFINE_DEBUG(Flex); // Define 'unsigned debugFlex()' // Functions called by lex rules: int yylexThis(); @@ -216,6 +202,7 @@ public: } int lexKwdLastState() const { return m_lexKwdLast; } static const char* tokenName(int tok); + static bool isStrengthToken(int tok); void ppPushText(const string& text) { m_ppBuffers.push_back(text); diff --git a/src/V3ParseSym.h b/src/V3ParseSym.h index 87edaef5a..b9e0d26e3 100644 --- a/src/V3ParseSym.h +++ b/src/V3ParseSym.h @@ -55,6 +55,9 @@ public: private: // METHODS + + VL_DEFINE_DEBUG_FUNCTIONS; + static VSymEnt* getTable(AstNode* nodep) { UASSERT_OBJ(nodep->user4p(), nodep, "Current symtable not found"); return nodep->user4u().toSymEnt(); @@ -115,7 +118,7 @@ public: if (VL_UNCOVERABLE(symCurrentp()->nodep() != nodep)) { // LCOV_EXCL_START if (debug()) { showUpward(); - dump(cout, "-mism: "); + dumpSelf(cout, "-mism: "); } nodep->v3fatalSrc("Symbols suggest ending " << symCurrentp()->nodep()->prettyTypeName() << " but parser thinks ending " @@ -133,7 +136,7 @@ public: } UINFO(1, "ParseSym Current: " << symCurrentp()->nodep() << endl); } // LCOV_EXCL_STOP - void dump(std::ostream& os, const string& indent = "") { m_syms.dump(os, indent); } + void dumpSelf(std::ostream& os, const string& indent = "") { m_syms.dumpSelf(os, indent); } AstNode* findEntUpward(const string& name) const { // Lookup the given string as an identifier, return type of the id, scanning upward VSymEnt* const foundp = symCurrentp()->findIdFallback(name); diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index 1b11a00b5..18952bfe8 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -24,6 +24,7 @@ #include "V3File.h" #include "V3GraphStream.h" #include "V3InstrCount.h" +#include "V3List.h" #include "V3Os.h" #include "V3PairingHeap.h" #include "V3PartitionGraph.h" @@ -35,10 +36,13 @@ #include #include #include +#include #include #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + class LogicMTask; class MTaskEdge; class MergeCandidate; @@ -217,10 +221,12 @@ private: // Store the outgoing and incoming edges in a heap sorted by the critical path length std::array m_edgeHeap; - // SiblingMC for which storage is owned by this MTask - std::set m_ownSibs; - // SiblingMC for which storage is owned by the opposite MTask - std::set m_farSibps; + // MTasks for which a SiblingMC exists with 'this' as the higher ID MTask (m_ap in SiblingMC) + std::set m_siblings; + // List of SiblingMCs for which this is the higher ID MTask (m_ap in SiblingMC) + V3List m_aSiblingMCs; + // List of SiblingMCs for which this is the lower ID MTask (m_bp in SiblingMC) + V3List m_bSiblingMCs; public: // CONSTRUCTORS @@ -240,15 +246,16 @@ public: } // METHODS - std::set& ownSibs() { return m_ownSibs; }; - std::set& farSibs() { return m_farSibps; }; + std::set& siblings() { return m_siblings; }; + V3List& aSiblingMCs() { return m_aSiblingMCs; }; + V3List& bSiblingMCs() { return m_bSiblingMCs; }; void moveAllVerticesFrom(LogicMTask* otherp) { // splice() is constant time m_vertices.splice(m_vertices.end(), otherp->m_vertices); m_cost += otherp->m_cost; } - virtual const VxList* vertexListp() const override { return &m_vertices; } + const VxList* vertexListp() const override { return &m_vertices; } static uint64_t incGeneration() { static uint64_t s_generation = 0; ++s_generation; @@ -258,10 +265,10 @@ public: // Use this instead of pointer-compares to compare LogicMTasks. Avoids // nondeterministic output. Also name mtasks based on this number in // the final C++ output. - virtual uint32_t id() const override { return m_serialId; } + uint32_t id() const override { return m_serialId; } void id(uint32_t id) { m_serialId = id; } // Abstract cost of every logic mtask - virtual uint32_t cost() const override { return m_cost; } + uint32_t cost() const override { return m_cost; } void setCost(uint32_t cost) { m_cost = cost; } // For tests only uint32_t stepCost() const { return stepCost(m_cost); } static uint32_t stepCost(uint32_t cost) { @@ -314,7 +321,7 @@ public: void checkRelativesCp(GraphWay way) const; - virtual string name() const override { + string name() const override { // Display forward and reverse critical path costs. This gives a quick // read on whether graph partitioning looks reasonable or bad. std::ostringstream out; @@ -385,7 +392,6 @@ public: static void dumpCpFilePrefixed(const V3Graph* graphp, const string& nameComment); private: - VL_DEBUG_FUNC; // Declare debug() VL_UNCOPYABLE(LogicMTask); }; @@ -465,10 +471,12 @@ static_assert(sizeof(MergeCandidate) == sizeof(MergeCandidateScoreboard::Node), // A pair of associated LogicMTask's that are merge candidates for sibling // contraction class SiblingMC final : public MergeCandidate { -private: LogicMTask* const m_ap; LogicMTask* const m_bp; + V3ListEnt m_aEnt; // List entry for m_ap->aSiblingMCs() + V3ListEnt m_bEnt; // List entry for m_bp->bSiblingMCs() + public: // CONSTRUCTORS SiblingMC() = delete; @@ -476,26 +484,33 @@ public: : MergeCandidate{/* isSiblingMC: */ true} , m_ap{ap} , m_bp{bp} { - // operator< and storage management depends on this + // Storage management depends on this UASSERT(ap->id() > bp->id(), "Should be ordered"); + UDEBUGONLY(UASSERT(ap->siblings().count(bp), "Should be in sibling map");); + m_aEnt.pushBack(m_ap->aSiblingMCs(), this); + m_bEnt.pushBack(m_bp->bSiblingMCs(), this); } ~SiblingMC() = default; + // METHODS + SiblingMC* aNextp() const { return m_aEnt.nextp(); } + SiblingMC* bNextp() const { return m_bEnt.nextp(); } + void unlinkA() { + VL_ATTR_UNUSED const size_t removed = m_ap->siblings().erase(m_bp); + UDEBUGONLY(UASSERT(removed == 1, "Should have been in sibling set");); + m_aEnt.unlink(m_ap->aSiblingMCs(), this); + } + void unlinkB() { m_bEnt.unlink(m_bp->bSiblingMCs(), this); } + LogicMTask* ap() const { return m_ap; } LogicMTask* bp() const { return m_bp; } bool mergeWouldCreateCycle() const { return (LogicMTask::pathExistsFrom(m_ap, m_bp, nullptr) || LogicMTask::pathExistsFrom(m_bp, m_ap, nullptr)); } - bool operator<(const SiblingMC& other) const { - if (m_ap->id() < other.m_ap->id()) return true; - if (m_ap->id() > other.m_ap->id()) return false; - return m_bp->id() < other.m_bp->id(); - } }; -static_assert(sizeof(SiblingMC) == sizeof(MergeCandidate) + 2 * sizeof(LogicMTask*), - "Should not have a vtable"); +static_assert(!std::is_polymorphic::value, "Should not have a vtable"); // GraphEdge for the MTask graph class MTaskEdge final : public V3GraphEdge, public MergeCandidate { @@ -812,7 +827,6 @@ public: } private: - VL_DEBUG_FUNC; // Declare debug() VL_UNCOPYABLE(PartParallelismEst); }; @@ -1056,7 +1070,6 @@ public: } private: - VL_DEBUG_FUNC; VL_UNCOPYABLE(PartPropagateCp); }; @@ -1385,12 +1398,13 @@ public: // New edges would be AC->B and B->AC which is not a DAG. // Do not allow this. if (mergeCanp->mergeWouldCreateCycle()) { - // Remove this edge from scoreboard so we don't keep + // Remove this candidate from scoreboard so we don't keep // reconsidering it on every loop. m_sb.remove(mergeCanp); if (SiblingMC* const smcp = mergeCanp->toSiblingMC()) { - smcp->bp()->farSibs().erase(smcp); - smcp->ap()->ownSibs().erase(*smcp); // Kills *smcp, so do last + smcp->unlinkA(); + smcp->unlinkB(); + delete smcp; } continue; } @@ -1455,29 +1469,45 @@ private: } void removeSiblingMCsWith(LogicMTask* mtaskp) { - for (const SiblingMC& pair : mtaskp->ownSibs()) { - m_sb.remove(const_cast(&pair)); - // Owner is always ap(), remove from the opposite side - pair.bp()->farSibs().erase(&pair); + for (SiblingMC *smcp = mtaskp->aSiblingMCs().begin(), *nextp; // lintok-begin-on-ref + smcp; smcp = nextp) { + nextp = smcp->aNextp(); + m_sb.remove(smcp); + smcp->unlinkB(); + delete smcp; } - for (const SiblingMC* const pairp : mtaskp->farSibs()) { - m_sb.remove(const_cast(pairp)); - // Owner is always ap(), remove from the opposite side - pairp->ap()->ownSibs().erase(*pairp); + for (SiblingMC *smcp = mtaskp->bSiblingMCs().begin(), *nextp; // lintok-begin-on-ref + smcp; smcp = nextp) { + nextp = smcp->bNextp(); + m_sb.remove(smcp); + smcp->unlinkA(); + delete smcp; } - mtaskp->ownSibs().clear(); - mtaskp->farSibs().clear(); + } + + void removeSiblingMCs(LogicMTask* recipientp, LogicMTask* donorp) { + // The lists here should be disjoint (there should be only one SiblingMC involving these + // two MTasks, and we removed that elsewhere), so no need for unlinking from the lists we + // are clearing. + removeSiblingMCsWith(recipientp); + removeSiblingMCsWith(donorp); + + // Clear the sibling map of the recipient. The donor will be deleted anyway, so we can + // leave that in a corrupt for efficiency. + recipientp->siblings().clear(); + recipientp->aSiblingMCs().reset(); + recipientp->bSiblingMCs().reset(); } void contract(MergeCandidate* mergeCanp) { LogicMTask* top = nullptr; LogicMTask* fromp = nullptr; - MTaskEdge* mergeEdgep = mergeCanp->toMTaskEdge(); + MTaskEdge* const mergeEdgep = mergeCanp->toMTaskEdge(); + SiblingMC* const mergeSibsp = mergeCanp->toSiblingMC(); if (mergeEdgep) { top = static_cast(mergeEdgep->top()); fromp = static_cast(mergeEdgep->fromp()); } else { - const SiblingMC* mergeSibsp = static_cast(mergeCanp); top = mergeSibsp->ap(); fromp = mergeSibsp->bp(); } @@ -1513,14 +1543,19 @@ private: const NewCp recipientNewCpRev = newCp(recipientp, donorp, mergeEdgep); const NewCp donorNewCpRev = newCp(donorp, recipientp, mergeEdgep); + m_sb.remove(mergeCanp); + if (mergeEdgep) { - // Remove and free the connecting edge. Must do this before - // propagating CP's below. - m_sb.remove(mergeCanp); + // Remove and free the connecting edge. Must do this before propagating CP's below. mergeEdgep->fromMTaskp()->removeRelativeMTask(mergeEdgep->toMTaskp()); mergeEdgep->fromMTaskp()->removeRelativeEdge(mergeEdgep); mergeEdgep->toMTaskp()->removeRelativeEdge(mergeEdgep); - VL_DO_CLEAR(mergeEdgep->unlinkDelete(), mergeEdgep = nullptr); + VL_DO_DANGLING(mergeEdgep->unlinkDelete(), mergeEdgep); + } else { + // Remove the siblingMC + mergeSibsp->unlinkA(); + mergeSibsp->unlinkB(); + VL_DO_DANGLING(delete mergeEdgep, mergeEdgep); } // This also updates cost and stepCost on recipientp @@ -1552,13 +1587,10 @@ private: m_forwardPropagator.go(); m_reversePropagator.go(); - // Remove all SiblingMCs that include donorp. This Includes the one - // we're merging, if we're merging a SiblingMC. - removeSiblingMCsWith(donorp); - // Remove all SiblingMCs that include recipientp also, so we can't - // get huge numbers of SiblingMCs. We'll recreate them below, up + // Remove all other SiblingMCs that include recipientp or donorp. We remove all siblingMCs + // of recipientp so we do not get huge numbers of SiblingMCs. We'll recreate them below, up // to a bounded number. - removeSiblingMCsWith(recipientp); + removeSiblingMCs(recipientp, donorp); // Redirect all edges, delete donorp partRedirectEdgesFrom(m_mtasksp, recipientp, donorp, &m_sb); @@ -1607,20 +1639,19 @@ private: void makeSiblingMC(LogicMTask* ap, LogicMTask* bp) { if (ap->id() < bp->id()) std::swap(ap, bp); - // The higher id vertex owns the storage - const auto emplaceResult = ap->ownSibs().emplace(ap, bp); - if (emplaceResult.second) { - SiblingMC* const newSibsp = const_cast(&(*emplaceResult.first)); - bp->farSibs().insert(newSibsp); - m_sb.add(newSibsp); - } else if (m_slowAsserts) { + // The higher id vertex owns the association set + const auto first = ap->siblings().insert(bp).second; + if (first) { + m_sb.add(new SiblingMC{ap, bp}); + } else if (VL_UNLIKELY(m_slowAsserts)) { // It's fine if we already have this SiblingMC, we may have // created it earlier. Just confirm that we have associated data. bool found = false; - for (const SiblingMC& sibs : ap->ownSibs()) { - UASSERT_OBJ(sibs.ap() == ap, ap, "Inconsistent SiblingMC"); - UASSERT_OBJ(m_sb.contains(&sibs), ap, "Must be on the scoreboard"); - if (sibs.bp() == bp) found = true; + for (const SiblingMC* smcp = ap->aSiblingMCs().begin(); // lintok-begin-on-ref + smcp; smcp = smcp->aNextp()) { + UASSERT_OBJ(smcp->ap() == ap, ap, "Inconsistent SiblingMC"); + UASSERT_OBJ(m_sb.contains(smcp), ap, "Must be on the scoreboard"); + if (smcp->bp() == bp) found = true; } UASSERT_OBJ(found, ap, "Sibling not found"); } @@ -1802,7 +1833,6 @@ public: } private: - VL_DEBUG_FUNC; // Declare debug() VL_UNCOPYABLE(PartContraction); }; @@ -1816,9 +1846,7 @@ private: bool m_hasDpiHazard = false; // Found a DPI import call. bool m_tracingCall = false; // Iterating into a CCall to a CFunc // METHODS - VL_DEBUG_FUNC; - - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { if (!m_tracingCall) return; m_tracingCall = false; if (nodep->dpiImportWrapper()) { @@ -1829,19 +1857,19 @@ private: } iterateChildren(nodep); } - virtual void visit(AstNodeCCall* nodep) override { + void visit(AstNodeCCall* nodep) override { iterateChildren(nodep); // Enter the function and trace it m_tracingCall = true; iterate(nodep->funcp()); } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit DpiImportCallVisitor(AstNode* nodep) { iterate(nodep); } bool hasDpiHazard() const { return m_hasDpiHazard; } - virtual ~DpiImportCallVisitor() override = default; + ~DpiImportCallVisitor() override = default; private: VL_UNCOPYABLE(DpiImportCallVisitor); @@ -2171,7 +2199,6 @@ public: private: VL_UNCOPYABLE(PartFixDataHazards); - VL_DEBUG_FUNC; }; //###################################################################### @@ -2493,7 +2520,7 @@ public: } } - if (debug() >= 4) schedule.dumpDotFilePrefixedAlways(mtaskGraph, "schedule"); + if (dumpGraph() >= 4) schedule.dumpDotFilePrefixedAlways(mtaskGraph, "schedule"); return schedule; } @@ -2551,7 +2578,6 @@ public: } private: - VL_DEBUG_FUNC; // Declare debug() VL_UNCOPYABLE(PartPackMTasks); }; @@ -2559,7 +2585,7 @@ private: // V3Partition implementation void V3Partition::debugMTaskGraphStats(const V3Graph* graphp, const string& stage) { - if (!debug()) return; + if (!debug() && !dump() && !dumpGraph()) return; UINFO(4, "\n"); UINFO(4, " Stats for " << stage << endl); @@ -2596,7 +2622,7 @@ void V3Partition::debugMTaskGraphStats(const V3Graph* graphp, const string& stag if (mtaskCount < 1000) { string filePrefix("ordermv_"); filePrefix += stage; - if (debug() >= 4) graphp->dumpDotFilePrefixedAlways(filePrefix); + if (dumpGraph() >= 4) graphp->dumpDotFilePrefixedAlways(filePrefix); } // Look only at the cost of each mtask, neglect communication cost. @@ -2697,9 +2723,7 @@ void V3Partition::go(V3Graph* mtasksp) { // For debug: print out the longest critical path. This allows us to // verify that the costs look reasonable, that we aren't combining // nodes that should probably be split, etc. - if (v3Global.opt.dumpTreeLevel(__FILE__) >= 3) { - LogicMTask::dumpCpFilePrefixed(mtasksp, "cp"); - } + if (dump() >= 3) LogicMTask::dumpCpFilePrefixed(mtasksp, "cp"); // Merge nodes that could present data hazards; see comment within. { @@ -3019,7 +3043,7 @@ static void addMTaskToFunction(const ThreadSchedule& schedule, const uint32_t th AstVar* const varp = new AstVar(fl, VVarType::MODULETEMP, name, mtaskStateDtypep); varp->valuep(new AstConst(fl, nDependencies)); varp->protect(false); // Do not protect as we still have references in AstText - modp->addStmtp(varp); + modp->addStmtsp(varp); // For now, reference is still via text bashing addStrStmt("vlSelf->" + name + +".waitUntilUpstreamDone(even_cycle);\n"); } @@ -3080,7 +3104,7 @@ static const std::vector createThreadFunctions(const ThreadSchedule& const uint32_t threadId = schedule.threadId(thread.front()); const string name{"__Vthread__" + tag + "__" + cvtToStr(threadId)}; AstCFunc* const funcp = new AstCFunc(fl, name, nullptr, "void"); - modp->addStmtp(funcp); + modp->addStmtsp(funcp); funcps.push_back(funcp); funcp->isStatic(true); // Uses void self pointer, so static and hand rolled funcp->isLoose(true); @@ -3108,7 +3132,7 @@ static const std::vector createThreadFunctions(const ThreadSchedule& = new AstVar(fl, VVarType::MODULETEMP, "__Vm_mtaskstate_final", mtaskStateDtypep); varp->valuep(new AstConst(fl, funcps.size())); varp->protect(false); // Do not protect as we still have references in AstText - modp->addStmtp(varp); + modp->addStmtsp(varp); return funcps; } diff --git a/src/V3Partition.h b/src/V3Partition.h index c358599f4..fc410c5c0 100644 --- a/src/V3Partition.h +++ b/src/V3Partition.h @@ -67,7 +67,6 @@ public: private: static void setupMTaskDeps(V3Graph* mtasksp, const Vx2MTaskMap* vx2mtaskp); - VL_DEBUG_FUNC; // Declare debug() VL_UNCOPYABLE(V3Partition); }; diff --git a/src/V3PartitionGraph.h b/src/V3PartitionGraph.h index b0eac05d3..d8ed603af 100644 --- a/src/V3PartitionGraph.h +++ b/src/V3PartitionGraph.h @@ -32,7 +32,7 @@ class AbstractMTask VL_NOT_FINAL : public V3GraphVertex { public: explicit AbstractMTask(V3Graph* graphp) : V3GraphVertex{graphp} {} - virtual ~AbstractMTask() override = default; + ~AbstractMTask() override = default; virtual uint32_t id() const = 0; virtual uint32_t cost() const = 0; }; @@ -44,12 +44,12 @@ public: // CONSTRUCTORS explicit AbstractLogicMTask(V3Graph* graphp) : AbstractMTask{graphp} {} - virtual ~AbstractLogicMTask() override = default; + ~AbstractLogicMTask() override = default; // METHODS // Set of logic vertices in this mtask. Order is not significant. virtual const VxList* vertexListp() const = 0; - virtual uint32_t id() const override = 0; // Unique id of this mtask. - virtual uint32_t cost() const override = 0; + uint32_t id() const override = 0; // Unique id of this mtask. + uint32_t cost() const override = 0; }; class ExecMTask final : public AbstractMTask { @@ -72,10 +72,10 @@ public: , m_bodyp{bodyp} , m_id{id} {} AstMTaskBody* bodyp() const { return m_bodyp; } - virtual uint32_t id() const override { return m_id; } + uint32_t id() const override { return m_id; } uint32_t priority() const { return m_priority; } void priority(uint32_t pri) { m_priority = pri; } - virtual uint32_t cost() const override { return m_cost; } + uint32_t cost() const override { return m_cost; } void cost(uint32_t cost) { m_cost = cost; } void predictStart(uint64_t time) { m_predictStart = time; } uint64_t predictStart() const { return m_predictStart; } @@ -85,7 +85,7 @@ public: // If this MTask maps to a C function, this should be the name return std::string{"__Vmtask"} + "__" + cvtToStr(m_id); } - virtual string name() const override { return std::string{"mt"} + cvtToStr(id()); } + string name() const override { return std::string{"mt"} + cvtToStr(id()); } string hashName() const { return m_hashName; } void hashName(const string& name) { m_hashName = name; } void dump(std::ostream& str) const { diff --git a/src/V3PreLex.h b/src/V3PreLex.h index 804b29e86..4389c506d 100644 --- a/src/V3PreLex.h +++ b/src/V3PreLex.h @@ -143,7 +143,7 @@ public: ~VPreStream() { lexStreamDepthAdd(-1); } private: - void lexStreamDepthAdd(int delta); + inline void lexStreamDepthAdd(int delta); }; //====================================================================== @@ -225,9 +225,8 @@ public: // Used only by V3PreLex.cpp and V3PreProc.cpp // Called by VPreStream void streamDepthAdd(int delta) { m_streamDepth += delta; } int streamDepth() const { return m_streamDepth; } - /// Utility - static int debug(); - static void debug(int level); + // Utility + static void setYYDebug(bool on); static string cleanDbgStrg(const string& in); private: @@ -237,6 +236,6 @@ private: void scanSwitchStream(VPreStream* streamp); }; -inline void VPreStream::lexStreamDepthAdd(int delta) { m_lexp->streamDepthAdd(delta); } +void VPreStream::lexStreamDepthAdd(int delta) { m_lexp->streamDepthAdd(delta); } #endif // Guard diff --git a/src/V3PreLex.l b/src/V3PreLex.l index bfe69e7c7..bc1dda03d 100644 --- a/src/V3PreLex.l +++ b/src/V3PreLex.l @@ -126,7 +126,7 @@ bom [\357\273\277] if (LEXP->m_protBytes > 0) { LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "multiple `pragma protected encoding sections"); } - res = sscanf(yytext + strlen("encoding"), " = (enctype = \"%15[A-Za-z0-9]\", line_length = %d, bytes = %d)", &enctype[0], &LEXP->m_protLength, &LEXP->m_protBytes); + res = sscanf(yytext + std::strlen("encoding"), " = (enctype = \"%15[A-Za-z0-9]\", line_length = %d, bytes = %d)", &enctype[0], &LEXP->m_protLength, &LEXP->m_protBytes); if (res == 0) LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "`pragma protected encoding must have an \"enctype\" field"); LEXP->m_encType = !VL_STRCASECMP(enctype, "uuencode") ? Enctype::UUENCODE : @@ -242,7 +242,7 @@ bom [\357\273\277] "`__LINE__" { FL_FWDC; static char buf[25]; VL_SNPRINTF(buf, 25, "%d", LEXP->curFilelinep()->lastLineno()); - yytext = buf; yyleng = strlen(yytext); + yytext = buf; yyleng = std::strlen(yytext); return VP_TEXT; } /* Pass-through strings */ @@ -462,11 +462,8 @@ void V3PreLex::pushStateIncFilename() { yymore(); } -void V3PreLex::debug(int level) { - yy_flex_debug = level; // Use --debugi-V3PreShell, if level<5 this level is 0 -} -int V3PreLex::debug() { - return yy_flex_debug; } +void V3PreLex::setYYDebug(bool on) { + yy_flex_debug = static_cast(on); } int V3PreLex::lex() { V3PreLex::s_currentLexp = this; // Tell parser where to get/put data diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index 59ba4398b..6aadb69f7 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -33,6 +33,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //====================================================================== // Build in LEX script @@ -112,8 +114,6 @@ public: using DefinesMap = std::map; using StrList = VInFilter::StrList; - // debug() -> see V3PreShellImp::debug; use --debugi-V3PreShell - // Defines list DefinesMap m_defines; ///< Map of defines @@ -250,19 +250,16 @@ public: void candidateDefines(VSpellCheck* spellerp) override; // METHODS, callbacks - virtual void comment(const string& text) override; // Comment detected (if keepComments==2) - virtual void include(const string& filename) override; // Request a include file be processed - virtual void undef(const string& name) override; + void comment(const string& text) override; // Comment detected (if keepComments==2) + void include(const string& filename) override; // Request a include file be processed + void undef(const string& name) override; virtual void undefineall(); - virtual void define(FileLine* fl, const string& name, const string& value, - const string& params, bool cmdline) override; - virtual string removeDefines(const string& text) override; // Remove defines in a text string + void define(FileLine* fl, const string& name, const string& value, const string& params, + bool cmdline) override; + string removeDefines(const string& text) override; // Remove defines in a text string // CONSTRUCTORS - V3PreProcImp() { - m_debug = 0; - m_states.push(ps_TOP); - } + V3PreProcImp() { m_states.push(ps_TOP); } void configure(FileLine* filelinep) { // configure() separate from constructor to avoid calling abstract functions m_preprocp = this; // Silly, but to make code more similar to Verilog-Perl @@ -273,7 +270,6 @@ public: m_lexp->m_keepComments = keepComments(); m_lexp->m_keepWhitespace = keepWhitespace(); m_lexp->m_pedantic = pedantic(); - debug(debug()); // Set lexer debug via V3PreProc::debug() method } ~V3PreProcImp() override { if (m_lexp) VL_DO_CLEAR(delete m_lexp, m_lexp = nullptr); @@ -395,7 +391,7 @@ string V3PreProcImp::commentCleanup(const string& text) { } bool V3PreProcImp::commentTokenMatch(string& cmdr, const char* strg) { - int len = strlen(strg); + int len = std::strlen(strg); if (VString::startsWith(cmdr, strg) && (cmdr[len] == '\0' || isspace(cmdr[len]))) { if (isspace(cmdr[len])) len++; cmdr = cmdr.substr(len); @@ -425,27 +421,27 @@ void V3PreProcImp::comment(const string& text) { bool synth = false; bool vlcomment = false; if ((cp[0] == 'v' || cp[0] == 'V') && VString::startsWith(cp + 1, "erilator")) { - cp += strlen("verilator"); + cp += std::strlen("verilator"); if (*cp == '_') { fileline()->v3error("Extra underscore in meta-comment;" " use /*verilator {...}*/ not /*verilator_{...}*/"); } vlcomment = true; } else if (VString::startsWith(cp, "synopsys")) { - cp += strlen("synopsys"); + cp += std::strlen("synopsys"); synth = true; if (*cp == '_') { fileline()->v3error("Extra underscore in meta-comment;" " use /*synopsys {...}*/ not /*synopsys_{...}*/"); } } else if (VString::startsWith(cp, "cadence")) { - cp += strlen("cadence"); + cp += std::strlen("cadence"); synth = true; } else if (VString::startsWith(cp, "pragma")) { - cp += strlen("pragma"); + cp += std::strlen("pragma"); synth = true; } else if (VString::startsWith(cp, "ambit synthesis")) { - cp += strlen("ambit synthesis"); + cp += std::strlen("ambit synthesis"); synth = true; } else { return; @@ -478,7 +474,7 @@ void V3PreProcImp::comment(const string& text) { string::size_type pos; if ((pos = cmd.find("public_flat_rw")) != string::npos) { // "/*verilator public_flat_rw @(foo) */" -> "/*verilator public_flat_rw*/ @(foo)" - cmd = cmd.substr(pos + strlen("public_flat_rw")); + cmd = cmd.substr(pos + std::strlen("public_flat_rw")); while (isspace(cmd[0])) cmd = cmd.substr(1); if (!printed) insertUnreadback("/*verilator public_flat_rw*/ " + cmd + " /**/"); } else { @@ -490,12 +486,6 @@ void V3PreProcImp::comment(const string& text) { //************************************************************************* // VPreProc Methods. -void V3PreProc::debug(int level) { - m_debug = level; - V3PreProcImp* idatap = static_cast(this); - if (idatap->m_lexp) idatap->m_lexp->debug(debug() >= 5 ? debug() : 0); -} - FileLine* V3PreProc::fileline() { const V3PreProcImp* idatap = static_cast(this); return idatap->m_lexp->m_tokFilelinep; @@ -777,6 +767,7 @@ string V3PreProcImp::defineSubst(VDefineRef* refp) { void V3PreProcImp::openFile(FileLine*, VInFilter* filterp, const string& filename) { // Open a new file, possibly overriding the current one which is active. if (m_incError) return; + m_lexp->setYYDebug(debug() >= 5); V3File::addSrcDepend(filename); // Read a list with the whole file. @@ -1593,7 +1584,7 @@ string V3PreProcImp::getline() { if (isEof()) return ""; const char* rtnp; bool gotEof = false; - while (nullptr == (rtnp = strchr(m_lineChars.c_str(), '\n')) && !gotEof) { + while (nullptr == (rtnp = std::strchr(m_lineChars.c_str(), '\n')) && !gotEof) { string buf; const int tok = getFinalToken(buf /*ref*/); if (debug() >= 5) { diff --git a/src/V3PreProc.h b/src/V3PreProc.h index f446a4f35..a14562a32 100644 --- a/src/V3PreProc.h +++ b/src/V3PreProc.h @@ -39,8 +39,7 @@ class V3PreProc VL_NOT_FINAL { // After creating, call open(), then getline() in a loop. The class will to the rest... protected: - // STATE - int m_debug; // Debugging + VL_DEFINE_DEBUG_FUNCTIONS; public: // CONSTANTS @@ -61,9 +60,6 @@ public: virtual bool isEof() const = 0; // Return true on EOF. virtual void insertUnreadback(const string& text) = 0; - int debug() const { return m_debug; } - void debug(int level); - FileLine* fileline(); ///< File/Line number for last getline call // CONTROL METHODS @@ -99,7 +95,7 @@ public: protected: // CONSTRUCTORS - V3PreProc() { m_debug = 0; } + V3PreProc() {} void configure(FileLine* fl); public: diff --git a/src/V3PreShell.cpp b/src/V3PreShell.cpp index f6e325f29..0502535af 100644 --- a/src/V3PreShell.cpp +++ b/src/V3PreShell.cpp @@ -28,6 +28,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### class V3PreShellImp final { @@ -41,21 +43,11 @@ protected: //--------------------------------------- // METHODS - static int debug(bool reset = false) { - static int level = -1; - if (VL_UNLIKELY(level < 0) || reset) { - level = v3Global.opt.debugSrcLevel(__FILE__); - if (s_preprocp) s_preprocp->debug(debug()); - } - return level; - } - void boot() { // Create the implementation pointer if (!s_preprocp) { FileLine* const cmdfl = new FileLine(FileLine::commandLineFilename()); s_preprocp = V3PreProc::createPreProc(cmdfl); - s_preprocp->debug(debug()); // Default defines FileLine* const prefl = new FileLine(FileLine::builtInFilename()); s_preprocp->defineCmdLine(prefl, "VERILATOR", "1"); // LEAK_OK @@ -88,8 +80,6 @@ protected: bool preproc(FileLine* fl, const string& modname, VInFilter* filterp, V3ParseImp* parsep, const string& errmsg) { // "" for no error - debug(true); // Recheck if debug on - first check was before command line passed - // Preprocess the given module, putting output in vppFilename UINFONL(1, " Preprocessing " << modname << endl); diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index e10f13458..48f8c5c31 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -36,6 +36,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + constexpr int STATIC_CONST_MIN_WIDTH = 256; // Minimum size to extract to static constant //###################################################################### @@ -62,8 +64,6 @@ private: VDouble0 m_extractedToConstPool; // Statistic tracking // METHODS - VL_DEBUG_FUNC; // Declare debug() - bool assignNoTemp(AstNodeAssign* nodep) { return (VN_IS(nodep->lhsp(), VarRef) && !AstVar::scVarRecurse(nodep->lhsp()) && VN_IS(nodep->rhsp(), Const)); @@ -151,11 +151,11 @@ private: } // VISITORS - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { UINFO(4, " MOD " << nodep << endl); iterateChildren(nodep); } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { VL_RESTORER(m_cfuncp); { m_cfuncp = nodep; @@ -167,7 +167,7 @@ private: m_assignLhs = false; if (m_cfuncp) m_stmtp = nodep; } - virtual void visit(AstWhile* nodep) override { + void visit(AstWhile* nodep) override { UINFO(4, " WHILE " << nodep << endl); startStatement(nodep); iterateAndNextNull(nodep->precondsp()); @@ -176,11 +176,11 @@ private: iterateAndNextNull(nodep->condp()); m_inWhilep = nullptr; startStatement(nodep); - iterateAndNextNull(nodep->bodysp()); + iterateAndNextNull(nodep->stmtsp()); iterateAndNextNull(nodep->incsp()); m_stmtp = nullptr; } - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { startStatement(nodep); { bool noopt = false; @@ -207,7 +207,7 @@ private: m_assignLhs = false; m_stmtp = nullptr; } - virtual void visit(AstNodeStmt* nodep) override { + void visit(AstNodeStmt* nodep) override { if (!nodep->isStatement()) { iterateChildren(nodep); return; @@ -217,7 +217,7 @@ private: iterateChildren(nodep); m_stmtp = nullptr; } - virtual void visit(AstTraceInc* nodep) override { + void visit(AstTraceInc* nodep) override { startStatement(nodep); m_inTracep = nodep; iterateChildren(nodep); @@ -271,31 +271,31 @@ private: iterateChildren(nodep); checkNode(nodep); } - virtual void visit(AstShiftL* nodep) override { visitShift(nodep); } - virtual void visit(AstShiftR* nodep) override { visitShift(nodep); } - virtual void visit(AstShiftRS* nodep) override { visitShift(nodep); } + void visit(AstShiftL* nodep) override { visitShift(nodep); } + void visit(AstShiftR* nodep) override { visitShift(nodep); } + void visit(AstShiftRS* nodep) override { visitShift(nodep); } // Operators - virtual void visit(AstNodeTermop* nodep) override { + void visit(AstNodeTermop* nodep) override { iterateChildren(nodep); checkNode(nodep); } - virtual void visit(AstNodeUniop* nodep) override { + void visit(AstNodeUniop* nodep) override { iterateChildren(nodep); checkNode(nodep); } - virtual void visit(AstNodeBiop* nodep) override { + void visit(AstNodeBiop* nodep) override { iterateChildren(nodep); checkNode(nodep); } - virtual void visit(AstRand* nodep) override { + void visit(AstRand* nodep) override { iterateChildren(nodep); checkNode(nodep); } - virtual void visit(AstUCFunc* nodep) override { + void visit(AstUCFunc* nodep) override { iterateChildren(nodep); checkNode(nodep); } - virtual void visit(AstSel* nodep) override { + void visit(AstSel* nodep) override { iterateAndNextNull(nodep->fromp()); { // Only the 'from' is part of the assignment LHS VL_RESTORER(m_assignLhs); @@ -305,7 +305,7 @@ private: } checkNode(nodep); } - virtual void visit(AstArraySel* nodep) override { + void visit(AstArraySel* nodep) override { iterateAndNextNull(nodep->fromp()); { // Only the 'from' is part of the assignment LHS VL_RESTORER(m_assignLhs); @@ -314,7 +314,7 @@ private: } checkNode(nodep); } - virtual void visit(AstAssocSel* nodep) override { + void visit(AstAssocSel* nodep) override { iterateAndNextNull(nodep->fromp()); { // Only the 'from' is part of the assignment LHS VL_RESTORER(m_assignLhs); @@ -323,13 +323,13 @@ private: } checkNode(nodep); } - virtual void visit(AstConst* nodep) override { + void visit(AstConst* nodep) override { iterateChildren(nodep); checkNode(nodep); } - virtual void visit(AstNodeCond* nodep) override { + void visit(AstNodeCond* nodep) override { iterateChildren(nodep); - if (nodep->expr1p()->isWide() && !VN_IS(nodep->condp(), Const) + if (nodep->thenp()->isWide() && !VN_IS(nodep->condp(), Const) && !VN_IS(nodep->condp(), VarRef)) { // We're going to need the expression several times in the expanded code, // so might as well make it a common expression @@ -339,7 +339,7 @@ private: } // Autoflush - virtual void visit(AstDisplay* nodep) override { + void visit(AstDisplay* nodep) override { startStatement(nodep); iterateChildren(nodep); m_stmtp = nullptr; @@ -356,7 +356,7 @@ private: } } } - virtual void visit(AstSFormatF* nodep) override { + void visit(AstSFormatF* nodep) override { iterateChildren(nodep); // Any strings sent to a display must be var of string data type, // to avoid passing a pointer to a temporary. @@ -370,8 +370,8 @@ private: //-------------------- // Default: Just iterate - virtual void visit(AstVar*) override {} // Don't hit varrefs under vars - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstVar*) override {} // Don't hit varrefs under vars + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -394,5 +394,5 @@ public: void V3Premit::premitAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { PremitVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("premit", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("premit", 0, dumpTree() >= 3); } diff --git a/src/V3ProtectLib.cpp b/src/V3ProtectLib.cpp index c9a7acf9b..7d04a1fc8 100644 --- a/src/V3ProtectLib.cpp +++ b/src/V3ProtectLib.cpp @@ -26,6 +26,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // ProtectLib top-level visitor @@ -64,7 +66,7 @@ private: bool m_hasClk = false; // True if the top module has sequential logic // VISITORS - virtual void visit(AstNetlist* nodep) override { + void visit(AstNetlist* nodep) override { m_vfilep = new AstVFile{nodep->fileline(), v3Global.opt.makeDir() + "/" + m_libName + ".sv"}; nodep->addFilesp(m_vfilep); @@ -74,7 +76,7 @@ private: iterateChildren(nodep); } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { if (!nodep->isTop()) { return; } else { @@ -95,7 +97,7 @@ private: } void addComment(AstTextBlock* txtp, FileLine* fl, const string& comment) { - txtp->addNodep(new AstComment{fl, comment}); + txtp->addNodesp(new AstComment{fl, comment}); } void hashComment(AstTextBlock* txtp, FileLine* fl) { @@ -143,7 +145,7 @@ private: // Module declaration m_modPortsp = new AstTextBlock{fl, "module " + m_libName + " (\n", false, true}; - txtp->addNodep(m_modPortsp); + txtp->addNodesp(m_modPortsp); txtp->addText(fl, ");\n\n"); // Timescale @@ -177,7 +179,7 @@ private: "(\n", false, true}; m_comboPortsp->addText(fl, "chandle handle__V\n"); - txtp->addNodep(m_comboPortsp); + txtp->addNodesp(m_comboPortsp); txtp->addText(fl, ");\n\n"); seqComment(txtp, fl); if (m_hasClk) { @@ -187,7 +189,7 @@ private: "(\n", false, true}; m_seqPortsp->addText(fl, "chandle handle__V\n"); - txtp->addNodep(m_seqPortsp); + txtp->addNodesp(m_seqPortsp); txtp->addText(fl, ");\n\n"); } comboIgnoreComment(txtp, fl); @@ -197,7 +199,7 @@ private: "(\n", false, true}; m_comboIgnorePortsp->addText(fl, "chandle handle__V\n"); - txtp->addNodep(m_comboIgnorePortsp); + txtp->addNodesp(m_comboIgnorePortsp); txtp->addText(fl, ");\n\n"); finalComment(txtp, fl); @@ -227,17 +229,17 @@ private: txtp->addText(fl, "\n"); m_comboDeclsp = new AstTextBlock{fl}; - txtp->addNodep(m_comboDeclsp); + txtp->addNodesp(m_comboDeclsp); m_seqDeclsp = new AstTextBlock{fl}; - txtp->addNodep(m_seqDeclsp); + txtp->addNodesp(m_seqDeclsp); m_tmpDeclsp = new AstTextBlock{fl}; - txtp->addNodep(m_tmpDeclsp); + txtp->addNodesp(m_tmpDeclsp); // CPP hash value addComment(txtp, fl, "Hash value to make sure this file and the corresponding"); addComment(txtp, fl, "library agree"); m_hashValuep = new AstTextBlock{fl, "localparam int protectlib_hash__V = 32'd"}; - txtp->addNodep(m_hashValuep); + txtp->addNodesp(m_hashValuep); txtp->addText(fl, "\n"); // Initial @@ -256,7 +258,7 @@ private: + m_libName + "_protectlib_combo_update(\n", false, true}; m_comboParamsp->addText(fl, "handle__V\n"); - txtp->addNodep(m_comboParamsp); + txtp->addNodesp(m_comboParamsp); txtp->addText(fl, ");\n"); txtp->addText(fl, "end\n\n"); @@ -264,21 +266,21 @@ private: if (m_hasClk) { addComment(txtp, fl, "Evaluate clock edges"); m_clkSensp = new AstTextBlock{fl, "always @(", false, true}; - txtp->addNodep(m_clkSensp); + txtp->addNodesp(m_clkSensp); txtp->addText(fl, ") begin\n"); m_comboIgnoreParamsp = new AstTextBlock{fl, m_libName + "_protectlib_combo_ignore(\n", false, true}; m_comboIgnoreParamsp->addText(fl, "handle__V\n"); - txtp->addNodep(m_comboIgnoreParamsp); + txtp->addNodesp(m_comboIgnoreParamsp); txtp->addText(fl, ");\n"); m_seqParamsp = new AstTextBlock{ fl, "last_seq_seqnum__V <= " + m_libName + "_protectlib_seq_update(\n", false, true}; m_seqParamsp->addText(fl, "handle__V\n"); - txtp->addNodep(m_seqParamsp); + txtp->addNodesp(m_seqParamsp); txtp->addText(fl, ");\n"); m_nbAssignsp = new AstTextBlock{fl}; - txtp->addNodep(m_nbAssignsp); + txtp->addNodesp(m_nbAssignsp); txtp->addText(fl, "end\n\n"); } @@ -288,13 +290,13 @@ private: if (m_hasClk) { m_seqAssignsp = new AstTextBlock{fl, "if (last_seq_seqnum__V > " "last_combo_seqnum__V) begin\n"}; - txtp->addNodep(m_seqAssignsp); + txtp->addNodesp(m_seqAssignsp); m_comboAssignsp = new AstTextBlock{fl, "end\nelse begin\n"}; - txtp->addNodep(m_comboAssignsp); + txtp->addNodesp(m_comboAssignsp); txtp->addText(fl, "end\n"); } else { m_comboAssignsp = new AstTextBlock{fl, ""}; - txtp->addNodep(m_comboAssignsp); + txtp->addNodesp(m_comboAssignsp); } txtp->addText(fl, "end\n\n"); @@ -341,7 +343,7 @@ private: + "_protectlib_check_hash" "(int protectlib_hash__V) {\n"); m_cHashValuep = new AstTextBlock{fl, "const int expected_hash__V = "}; - txtp->addNodep(m_cHashValuep); + txtp->addNodesp(m_cHashValuep); txtp->addText(fl, /**/ "if (protectlib_hash__V != expected_hash__V) {\n"); txtp->addText(fl, /****/ "fprintf(stderr, \"%%Error: cannot use " + m_libName + " library, " @@ -364,13 +366,13 @@ private: m_cComboParamsp = new AstTextBlock{ fl, "long long " + m_libName + "_protectlib_combo_update(\n", false, true}; m_cComboParamsp->addText(fl, "void* vhandlep__V\n"); - txtp->addNodep(m_cComboParamsp); + txtp->addNodesp(m_cComboParamsp); txtp->addText(fl, ")\n"); m_cComboInsp = new AstTextBlock{fl, "{\n"}; castPtr(fl, m_cComboInsp); - txtp->addNodep(m_cComboInsp); + txtp->addNodesp(m_cComboInsp); m_cComboOutsp = new AstTextBlock{fl, "handlep__V->eval();\n"}; - txtp->addNodep(m_cComboOutsp); + txtp->addNodesp(m_cComboOutsp); txtp->addText(fl, "return handlep__V->m_seqnum++;\n"); txtp->addText(fl, "}\n\n"); @@ -379,13 +381,13 @@ private: m_cSeqParamsp = new AstTextBlock{ fl, "long long " + m_libName + "_protectlib_seq_update(\n", false, true}; m_cSeqParamsp->addText(fl, "void* vhandlep__V\n"); - txtp->addNodep(m_cSeqParamsp); + txtp->addNodesp(m_cSeqParamsp); txtp->addText(fl, ")\n"); m_cSeqClksp = new AstTextBlock{fl, "{\n"}; castPtr(fl, m_cSeqClksp); - txtp->addNodep(m_cSeqClksp); + txtp->addNodesp(m_cSeqClksp); m_cSeqOutsp = new AstTextBlock{fl, "handlep__V->eval();\n"}; - txtp->addNodep(m_cSeqOutsp); + txtp->addNodesp(m_cSeqOutsp); txtp->addText(fl, "return handlep__V->m_seqnum++;\n"); txtp->addText(fl, "}\n\n"); } @@ -394,7 +396,7 @@ private: m_cIgnoreParamsp = new AstTextBlock{ fl, "void " + m_libName + "_protectlib_combo_ignore(\n", false, true}; m_cIgnoreParamsp->addText(fl, "void* vhandlep__V\n"); - txtp->addNodep(m_cIgnoreParamsp); + txtp->addNodesp(m_cIgnoreParamsp); txtp->addText(fl, ")\n"); txtp->addText(fl, "{ }\n\n"); @@ -422,7 +424,7 @@ private: m_cfilep->tblockp(txtp); } - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { if (!nodep->isIO()) return; if (nodep->direction() == VDirection::INPUT) { if (nodep->isUsedClock() || nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES) { @@ -439,7 +441,7 @@ private: } } - virtual void visit(AstNode*) override {} + void visit(AstNode*) override {} string cInputConnection(AstVar* varp) { return V3Task::assignDpiToInternal("handlep__V->" + varp->name(), varp); @@ -448,7 +450,7 @@ private: void handleClock(AstVar* varp) { FileLine* const fl = varp->fileline(); handleInput(varp); - m_seqPortsp->addNodep(varp->cloneTree(false)); + m_seqPortsp->addNodesp(varp->cloneTree(false)); if (m_hasClk) { m_seqParamsp->addText(fl, varp->name() + "\n"); m_clkSensp->addText(fl, "posedge " + varp->name() + " or negedge " + varp->name()); @@ -460,30 +462,30 @@ private: void handleDataInput(AstVar* varp) { FileLine* const fl = varp->fileline(); handleInput(varp); - m_comboPortsp->addNodep(varp->cloneTree(false)); + m_comboPortsp->addNodesp(varp->cloneTree(false)); m_comboParamsp->addText(fl, varp->name() + "\n"); - m_comboIgnorePortsp->addNodep(varp->cloneTree(false)); + m_comboIgnorePortsp->addNodesp(varp->cloneTree(false)); if (m_hasClk) m_comboIgnoreParamsp->addText(fl, varp->name() + "\n"); m_cComboParamsp->addText(fl, varp->dpiArgType(true, false) + "\n"); m_cComboInsp->addText(fl, cInputConnection(varp)); m_cIgnoreParamsp->addText(fl, varp->dpiArgType(true, false) + "\n"); } - void handleInput(AstVar* varp) { m_modPortsp->addNodep(varp->cloneTree(false)); } + void handleInput(AstVar* varp) { m_modPortsp->addNodesp(varp->cloneTree(false)); } static void addLocalVariable(AstTextBlock* textp, AstVar* varp, const char* suffix) { AstVar* const newVarp = new AstVar{varp->fileline(), VVarType::VAR, varp->name() + suffix, varp->dtypep()}; - textp->addNodep(newVarp); + textp->addNodesp(newVarp); } void handleOutput(AstVar* varp) { FileLine* const fl = varp->fileline(); - m_modPortsp->addNodep(varp->cloneTree(false)); - m_comboPortsp->addNodep(varp->cloneTree(false)); + m_modPortsp->addNodesp(varp->cloneTree(false)); + m_comboPortsp->addNodesp(varp->cloneTree(false)); m_comboParamsp->addText(fl, varp->name() + "_combo__V\n"); if (m_hasClk) { - m_seqPortsp->addNodep(varp->cloneTree(false)); + m_seqPortsp->addNodesp(varp->cloneTree(false)); m_seqParamsp->addText(fl, varp->name() + "_tmp__V\n"); } diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 0ac20c3b7..3677a1071 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -31,6 +31,8 @@ #include "V3Ast.h" +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Visitor that marks classes needing a randomize() method @@ -47,8 +49,6 @@ private: BaseToDerivedMap m_baseToDerivedMap; // Mapping from base classes to classes that extend them // METHODS - VL_DEBUG_FUNC; - void markMembers(AstClass* nodep) { for (auto* classp = nodep; classp; classp = classp->extendsp() ? classp->extendsp()->classp() : nullptr) { @@ -82,7 +82,7 @@ private: } // VISITORS - virtual void visit(AstClass* nodep) override { + void visit(AstClass* nodep) override { iterateChildren(nodep); if (nodep->extendsp()) { // Save pointer to derived class @@ -90,7 +90,7 @@ private: m_baseToDerivedMap[basep].insert(nodep); } } - virtual void visit(AstMethodCall* nodep) override { + void visit(AstMethodCall* nodep) override { iterateChildren(nodep); if (nodep->name() != "randomize") return; if (const AstClassRefDType* const classRefp @@ -100,7 +100,7 @@ private: markMembers(classp); } } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -108,7 +108,7 @@ public: iterate(nodep); markAllDerived(); } - virtual ~RandomizeMarkVisitor() override = default; + ~RandomizeMarkVisitor() override = default; }; //###################################################################### @@ -127,8 +127,6 @@ private: size_t m_enumValueTabCount = 0; // Number of tables with enum values created // METHODS - VL_DEBUG_FUNC; - AstVar* enumValueTabp(AstEnumDType* nodep) { if (nodep->user2p()) return VN_AS(nodep->user2p(), Var); UINFO(9, "Construct Venumvaltab " << nodep << endl); @@ -144,7 +142,7 @@ private: varp->isStatic(true); varp->valuep(initp); // Add to root, as don't know module we are in, and aids later structure sharing - v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(varp); + v3Global.rootp()->dollarUnitPkgAddp()->addStmtsp(varp); UASSERT_OBJ(nodep->itemsp(), nodep, "Enum without items"); for (AstEnumItem* itemp = nodep->itemsp(); itemp; itemp = VN_AS(itemp->nextp(), EnumItem)) { @@ -199,7 +197,7 @@ private: } // VISITORS - virtual void visit(AstClass* nodep) override { + void visit(AstClass* nodep) override { iterateChildren(nodep); if (!nodep->user1()) return; // Doesn't need randomize, or already processed UINFO(9, "Define randomize() for " << nodep << endl); @@ -241,12 +239,12 @@ private: } nodep->user1(false); } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit RandomizeVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~RandomizeVisitor() override = default; + ~RandomizeVisitor() override = default; }; //###################################################################### @@ -258,7 +256,7 @@ void V3Randomize::randomizeNetlist(AstNetlist* nodep) { const RandomizeMarkVisitor markVisitor{nodep}; RandomizeVisitor{nodep}; } - V3Global::dumpCheckGlobalTree("randomize", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("randomize", 0, dumpTree() >= 3); } AstFunc* V3Randomize::newRandomizeFunc(AstClass* nodep) { diff --git a/src/V3Reloop.cpp b/src/V3Reloop.cpp index 19a4363ca..db48e6b2e 100644 --- a/src/V3Reloop.cpp +++ b/src/V3Reloop.cpp @@ -40,6 +40,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### class ReloopVisitor final : public VNVisitor { @@ -66,7 +68,6 @@ private: uint32_t m_mgIndexHi = 0; // Merge range // METHODS - VL_DEBUG_FUNC; // Declare debug() static AstVar* findCreateVarTemp(FileLine* fl, AstCFunc* cfuncp) { AstVar* varp = VN_AS(cfuncp->user1p(), Var); @@ -114,7 +115,7 @@ private: AstWhile* const whilep = new AstWhile(fl, condp, nullptr, incp); initp->addNext(whilep); bodyp->replaceWith(initp); - whilep->addBodysp(bodyp); + whilep->addStmtsp(bodyp); // Replace constant index with new loop index AstNode* const offsetp @@ -151,7 +152,7 @@ private: } // VISITORS - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { VL_RESTORER(m_cfuncp); { m_cfuncp = nodep; @@ -159,7 +160,7 @@ private: mergeEnd(); // Finish last pending merge, if any } } - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { if (!m_cfuncp) return; // Left select WordSel or ArraySel @@ -250,14 +251,14 @@ private: UINFO(9, "Start merge i=" << lindex << " o=" << m_mgOffset << nodep << endl); } //-------------------- - virtual void visit(AstVar*) override {} // Accelerate - virtual void visit(AstNodeMath*) override {} // Accelerate - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstVar*) override {} // Accelerate + void visit(AstNodeMath*) override {} // Accelerate + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit ReloopVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~ReloopVisitor() override { + ~ReloopVisitor() override { V3Stats::addStat("Optimizations, Reloops", m_statReloops); V3Stats::addStat("Optimizations, Reloop iterations", m_statReItems); } @@ -269,5 +270,5 @@ public: void V3Reloop::reloopAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { ReloopVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("reloop", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6); + V3Global::dumpCheckGlobalTree("reloop", 0, dumpTree() >= 6); } diff --git a/src/V3Scope.cpp b/src/V3Scope.cpp index e39c1aa93..c0694e2ab 100644 --- a/src/V3Scope.cpp +++ b/src/V3Scope.cpp @@ -34,6 +34,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Scope class functions @@ -62,7 +64,6 @@ private: m_varRefScopes; // Varrefs-in-scopes needing fixup when done // METHODS - VL_DEBUG_FUNC; // Declare debug() void cleanupVarRefs() { for (const auto& itr : m_varRefScopes) { @@ -81,7 +82,7 @@ private: } // VISITORS - virtual void visit(AstNetlist* nodep) override { + void visit(AstNetlist* nodep) override { AstNodeModule* const modp = nodep->topModulep(); if (!modp) { nodep->v3error("No top level module found"); @@ -93,7 +94,7 @@ private: iterate(modp); cleanupVarRefs(); } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { // Create required blocks and add to module string scopename; if (!m_aboveScopep) { @@ -135,7 +136,7 @@ private: if (m_modp->isTop()) { v3Global.rootp()->createTopScope(m_scopep); } else { - m_modp->addStmtp(m_scopep); + m_modp->addStmtsp(m_scopep); } // Copy blocks into this scope @@ -144,7 +145,7 @@ private: // ***Note m_scopep is passed back to the caller of the routine (above) } - virtual void visit(AstClass* nodep) override { + void visit(AstClass* nodep) override { // Create required blocks and add to module VL_RESTORER(m_scopep); VL_RESTORER(m_aboveCellp); @@ -177,71 +178,71 @@ private: iterateChildren(nodep); } } - virtual void visit(AstCellInline* nodep) override { // + void visit(AstCellInline* nodep) override { // nodep->scopep(m_scopep); } - virtual void visit(AstActive* nodep) override { // LCOV_EXCL_LINE + void visit(AstActive* nodep) override { // LCOV_EXCL_LINE nodep->v3fatalSrc("Actives now made after scoping"); } - virtual void visit(AstNodeProcedure* nodep) override { + void visit(AstNodeProcedure* nodep) override { // Add to list of blocks under this scope UINFO(4, " Move " << nodep << endl); AstNode* const clonep = nodep->cloneTree(false); nodep->user2p(clonep); - m_scopep->addActivep(clonep); + m_scopep->addBlocksp(clonep); iterateChildren(clonep); // We iterate under the *clone* } - virtual void visit(AstAssignAlias* nodep) override { + void visit(AstAssignAlias* nodep) override { // Add to list of blocks under this scope UINFO(4, " Move " << nodep << endl); AstNode* const clonep = nodep->cloneTree(false); nodep->user2p(clonep); - m_scopep->addActivep(clonep); + m_scopep->addBlocksp(clonep); iterateChildren(clonep); // We iterate under the *clone* } - virtual void visit(AstAssignVarScope* nodep) override { + void visit(AstAssignVarScope* nodep) override { // Copy under the scope but don't recurse UINFO(4, " Move " << nodep << endl); AstNode* const clonep = nodep->cloneTree(false); nodep->user2p(clonep); - m_scopep->addActivep(clonep); + m_scopep->addBlocksp(clonep); iterateChildren(clonep); // We iterate under the *clone* } - virtual void visit(AstAssignW* nodep) override { + void visit(AstAssignW* nodep) override { // Add to list of blocks under this scope UINFO(4, " Move " << nodep << endl); AstNode* const clonep = nodep->cloneTree(false); nodep->user2p(clonep); - m_scopep->addActivep(clonep); + m_scopep->addBlocksp(clonep); iterateChildren(clonep); // We iterate under the *clone* } - virtual void visit(AstAlwaysPublic* nodep) override { + void visit(AstAlwaysPublic* nodep) override { // Add to list of blocks under this scope UINFO(4, " Move " << nodep << endl); AstNode* const clonep = nodep->cloneTree(false); nodep->user2p(clonep); - m_scopep->addActivep(clonep); + m_scopep->addBlocksp(clonep); iterateChildren(clonep); // We iterate under the *clone* } - virtual void visit(AstCoverToggle* nodep) override { + void visit(AstCoverToggle* nodep) override { // Add to list of blocks under this scope UINFO(4, " Move " << nodep << endl); AstNode* const clonep = nodep->cloneTree(false); nodep->user2p(clonep); - m_scopep->addActivep(clonep); + m_scopep->addBlocksp(clonep); iterateChildren(clonep); // We iterate under the *clone* } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { // Add to list of blocks under this scope UINFO(4, " CFUNC " << nodep << endl); AstCFunc* const clonep = nodep->cloneTree(false); nodep->user2p(clonep); - m_scopep->addActivep(clonep); + m_scopep->addBlocksp(clonep); clonep->scopep(m_scopep); // We iterate under the *clone* iterateChildren(clonep); } - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstNodeFTask* nodep) override { // Add to list of blocks under this scope UINFO(4, " FTASK " << nodep << endl); AstNodeFTask* clonep; @@ -253,11 +254,11 @@ private: clonep = nodep->cloneTree(false); } nodep->user2p(clonep); - m_scopep->addActivep(clonep); + m_scopep->addBlocksp(clonep); // We iterate under the *clone* iterateChildren(clonep); } - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { // Make new scope variable if (!nodep->user1p()) { AstVarScope* const varscp = new AstVarScope(nodep->fileline(), m_scopep, nodep); @@ -272,10 +273,10 @@ private: } UASSERT_OBJ(m_scopep, nodep, "No scope for var"); m_varScopes.emplace(std::make_pair(nodep, m_scopep), varscp); - m_scopep->addVarp(varscp); + m_scopep->addVarsp(varscp); } } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { // VarRef needs to point to VarScope // Make sure variable has made user1p. UASSERT_OBJ(nodep->varp(), nodep, "Unlinked"); @@ -289,33 +290,33 @@ private: m_varRefScopes.emplace(nodep, m_scopep); } } - virtual void visit(AstScopeName* nodep) override { + void visit(AstScopeName* nodep) override { // If there's a %m in the display text, we add a special node that will contain the name() const string prefix = std::string{"__DOT__"} + m_scopep->name(); // TOP and above will be the user's name(). // Note 'TOP.' is stripped by scopePrettyName // To keep correct visual order, must add before other Text's - AstNode* afterp = nodep->scopeAttrp(); + AstText* afterp = nodep->scopeAttrp(); if (afterp) afterp->unlinkFrBackWithNext(); - nodep->scopeAttrp(new AstText(nodep->fileline(), prefix)); - if (afterp) nodep->scopeAttrp(afterp); + nodep->addScopeAttrp(new AstText(nodep->fileline(), prefix)); + if (afterp) nodep->addScopeAttrp(afterp); afterp = nodep->scopeEntrp(); if (afterp) afterp->unlinkFrBackWithNext(); - nodep->scopeEntrp(new AstText(nodep->fileline(), prefix)); - if (afterp) nodep->scopeEntrp(afterp); + nodep->addScopeEntrp(new AstText(nodep->fileline(), prefix)); + if (afterp) nodep->addScopeEntrp(afterp); iterateChildren(nodep); } - virtual void visit(AstScope* nodep) override { + void visit(AstScope* nodep) override { // Scope that was made by this module for different cell; // Want to ignore blocks under it, so just do nothing } //-------------------- - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit ScopeVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~ScopeVisitor() override = default; + ~ScopeVisitor() override = default; }; //###################################################################### @@ -327,10 +328,9 @@ private: AstScope* m_scopep = nullptr; // Current scope we are building // METHODS - VL_DEBUG_FUNC; // Declare debug() // VISITORS - virtual void visit(AstScope* nodep) override { + void visit(AstScope* nodep) override { // Want to ignore blocks under it VL_RESTORER(m_scopep); { @@ -351,20 +351,20 @@ private: } } - virtual void visit(AstNodeProcedure* nodep) override { movedDeleteOrIterate(nodep); } - virtual void visit(AstAssignAlias* nodep) override { movedDeleteOrIterate(nodep); } - virtual void visit(AstAssignVarScope* nodep) override { movedDeleteOrIterate(nodep); } - virtual void visit(AstAssignW* nodep) override { movedDeleteOrIterate(nodep); } - virtual void visit(AstAlwaysPublic* nodep) override { movedDeleteOrIterate(nodep); } - virtual void visit(AstCoverToggle* nodep) override { movedDeleteOrIterate(nodep); } - virtual void visit(AstNodeFTask* nodep) override { movedDeleteOrIterate(nodep); } - virtual void visit(AstCFunc* nodep) override { movedDeleteOrIterate(nodep); } + void visit(AstNodeProcedure* nodep) override { movedDeleteOrIterate(nodep); } + void visit(AstAssignAlias* nodep) override { movedDeleteOrIterate(nodep); } + void visit(AstAssignVarScope* nodep) override { movedDeleteOrIterate(nodep); } + void visit(AstAssignW* nodep) override { movedDeleteOrIterate(nodep); } + void visit(AstAlwaysPublic* nodep) override { movedDeleteOrIterate(nodep); } + void visit(AstCoverToggle* nodep) override { movedDeleteOrIterate(nodep); } + void visit(AstNodeFTask* nodep) override { movedDeleteOrIterate(nodep); } + void visit(AstCFunc* nodep) override { movedDeleteOrIterate(nodep); } - virtual void visit(AstVarXRef* nodep) override { + void visit(AstVarXRef* nodep) override { // The crossrefs are dealt with in V3LinkDot nodep->varp(nullptr); } - virtual void visit(AstNodeFTaskRef* nodep) override { + void visit(AstNodeFTaskRef* nodep) override { // The crossrefs are dealt with in V3LinkDot UINFO(9, " Old pkg-taskref " << nodep << endl); if (nodep->classOrPackagep()) { @@ -380,7 +380,7 @@ private: } iterateChildren(nodep); } - virtual void visit(AstModportFTaskRef* nodep) override { + void visit(AstModportFTaskRef* nodep) override { // The modport persists only for xml dump // The crossrefs are dealt with in V3LinkDot nodep->ftaskp(nullptr); @@ -388,12 +388,12 @@ private: } //-------------------- - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit ScopeCleanupVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~ScopeCleanupVisitor() override = default; + ~ScopeCleanupVisitor() override = default; }; //###################################################################### @@ -405,5 +405,5 @@ void V3Scope::scopeAll(AstNetlist* nodep) { const ScopeVisitor visitor{nodep}; ScopeCleanupVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("scope", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("scope", 0, dumpTree() >= 3); } diff --git a/src/V3SenTree.h b/src/V3SenTree.h index c140580a0..636476b6f 100644 --- a/src/V3SenTree.h +++ b/src/V3SenTree.h @@ -64,7 +64,7 @@ public: // Not found, create a new one AstSenTree* const newSenTreep = senTreep->cloneTree(false); - m_topScopep->addSenTreep(newSenTreep); + m_topScopep->addSenTreesp(newSenTreep); m_trees.emplace(*newSenTreep); return newSenTreep; } diff --git a/src/V3Simulate.h b/src/V3Simulate.h index 0c9c6f43f..7c70e4ba1 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -115,7 +115,7 @@ private: std::vector m_reclaimValuesp; // List of allocated string numbers // Note level 8&9 include debugging each simulation value - VL_DEBUG_FUNC; // Declare debug() + VL_DEFINE_DEBUG_FUNCTIONS; // Potentially very slow, intended for debugging string prettyNumber(const V3Number* nump, AstNodeDType* dtypep) { @@ -397,15 +397,15 @@ private: } // VISITORS - virtual void visit(AstAlways* nodep) override { + void visit(AstAlways* nodep) override { if (jumpingOver(nodep)) return; checkNodeInfo(nodep); iterateChildren(nodep); } - virtual void visit(AstSenTree* nodep) override { + void visit(AstSenTree* nodep) override { // Sensitivities aren't inputs per se; we'll keep our tree under the same sens. } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { if (jumpingOver(nodep)) return; if (!optimizable()) return; // Accelerate UASSERT_OBJ(nodep->varp(), nodep, "Unlinked"); @@ -473,7 +473,7 @@ private: } } } - virtual void visit(AstVarXRef* nodep) override { + void visit(AstVarXRef* nodep) override { if (jumpingOver(nodep)) return; if (m_scoped) { badNodeType(nodep); @@ -483,7 +483,7 @@ private: "allowed in constant functions"); } } - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstNodeFTask* nodep) override { if (jumpingOver(nodep)) return; if (!m_params) { badNodeType(nodep); @@ -503,7 +503,7 @@ private: checkNodeInfo(nodep); iterateChildren(nodep); } - virtual void visit(AstNodeIf* nodep) override { + void visit(AstNodeIf* nodep) override { if (jumpingOver(nodep)) return; UINFO(5, " IF " << nodep << endl); checkNodeInfo(nodep); @@ -513,22 +513,22 @@ private: iterateAndNextNull(nodep->condp()); if (optimizable()) { if (fetchConst(nodep->condp())->num().isNeqZero()) { - iterateAndNextNull(nodep->ifsp()); + iterateAndNextNull(nodep->thensp()); } else { iterateAndNextNull(nodep->elsesp()); } } } } - virtual void visit(AstConst* nodep) override { + void visit(AstConst* nodep) override { checkNodeInfo(nodep); if (!m_checkOnly && optimizable()) newValue(nodep, nodep); } - virtual void visit(AstInitArray* nodep) override { + void visit(AstInitArray* nodep) override { checkNodeInfo(nodep); if (!m_checkOnly && optimizable()) newValue(nodep, nodep); } - virtual void visit(AstEnumItemRef* nodep) override { + void visit(AstEnumItemRef* nodep) override { checkNodeInfo(nodep); UASSERT_OBJ(nodep->itemp(), nodep, "Not linked"); if (!m_checkOnly && optimizable()) { @@ -541,7 +541,7 @@ private: } } } - virtual void visit(AstNodeUniop* nodep) override { + void visit(AstNodeUniop* nodep) override { if (!optimizable()) return; // Accelerate checkNodeInfo(nodep); iterateChildren(nodep); @@ -549,7 +549,7 @@ private: nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num()); } } - virtual void visit(AstNodeBiop* nodep) override { + void visit(AstNodeBiop* nodep) override { if (!optimizable()) return; // Accelerate checkNodeInfo(nodep); iterateChildren(nodep); @@ -558,7 +558,7 @@ private: fetchConst(nodep->rhsp())->num()); } } - virtual void visit(AstNodeTriop* nodep) override { + void visit(AstNodeTriop* nodep) override { if (!optimizable()) return; // Accelerate checkNodeInfo(nodep); iterateChildren(nodep); @@ -568,7 +568,7 @@ private: fetchConst(nodep->thsp())->num()); } } - virtual void visit(AstNodeQuadop* nodep) override { + void visit(AstNodeQuadop* nodep) override { if (!optimizable()) return; // Accelerate checkNodeInfo(nodep); iterateChildren(nodep); @@ -579,7 +579,7 @@ private: fetchConst(nodep->fhsp())->num()); } } - virtual void visit(AstLogAnd* nodep) override { + void visit(AstLogAnd* nodep) override { // Need to short circuit if (!optimizable()) return; // Accelerate checkNodeInfo(nodep); @@ -597,7 +597,7 @@ private: } } } - virtual void visit(AstLogOr* nodep) override { + void visit(AstLogOr* nodep) override { // Need to short circuit if (!optimizable()) return; // Accelerate checkNodeInfo(nodep); @@ -615,7 +615,7 @@ private: } } } - virtual void visit(AstLogIf* nodep) override { + void visit(AstLogIf* nodep) override { // Need to short circuit, same as (!A || B) if (!optimizable()) return; // Accelerate checkNodeInfo(nodep); @@ -625,8 +625,8 @@ private: iterate(nodep->lhsp()); if (optimizable()) { if (fetchConst(nodep->lhsp())->num().isEqZero()) { - const AstConst cnst(nodep->fileline(), AstConst::WidthedValue(), 1, - 1); // a one + const AstConst cnst{nodep->fileline(), AstConst::WidthedValue{}, 1, + 1}; // a one newValue(nodep, &cnst); // a one } else { iterate(nodep->rhsp()); @@ -635,7 +635,7 @@ private: } } } - virtual void visit(AstNodeCond* nodep) override { + void visit(AstNodeCond* nodep) override { // We could use above visit(AstNodeTriop), but need to do short circuiting. // It's also slower even O(n^2) to evaluate both sides when we // really only need to evaluate one side. @@ -647,11 +647,11 @@ private: iterate(nodep->condp()); if (optimizable()) { if (fetchConst(nodep->condp())->num().isNeqZero()) { - iterate(nodep->expr1p()); - newValue(nodep, fetchValue(nodep->expr1p())); + iterate(nodep->thenp()); + newValue(nodep, fetchValue(nodep->thenp())); } else { - iterate(nodep->expr2p()); - newValue(nodep, fetchValue(nodep->expr2p())); + iterate(nodep->elsep()); + newValue(nodep, fetchValue(nodep->elsep())); } } } @@ -755,7 +755,7 @@ private: } } - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { if (jumpingOver(nodep)) return; if (!optimizable()) return; // Accelerate checkNodeInfo(nodep); @@ -795,7 +795,7 @@ private: } m_inDlyAssign = false; } - virtual void visit(AstArraySel* nodep) override { + void visit(AstArraySel* nodep) override { checkNodeInfo(nodep); iterateChildren(nodep); if (AstInitArray* const initp = VN_CAST(fetchValueNull(nodep->fromp()), InitArray)) { @@ -812,11 +812,11 @@ private: clearOptimizable(nodep, "Array select of non-array"); } } - virtual void visit(AstBegin* nodep) override { + void visit(AstBegin* nodep) override { checkNodeInfo(nodep); iterateChildren(nodep); } - virtual void visit(AstNodeCase* nodep) override { + void visit(AstNodeCase* nodep) override { if (jumpingOver(nodep)) return; UINFO(5, " CASE " << nodep << endl); checkNodeInfo(nodep); @@ -835,7 +835,7 @@ private: V3Number match{nodep, 1}; match.opEq(fetchConst(nodep->exprp())->num(), fetchConst(ep)->num()); if (match.isNeqZero()) { - iterateAndNextNull(itemp->bodysp()); + iterateAndNextNull(itemp->stmtsp()); hit = true; } } @@ -847,27 +847,27 @@ private: itemp = VN_AS(itemp->nextp(), CaseItem)) { if (hit) break; if (!hit && itemp->isDefault()) { - iterateAndNextNull(itemp->bodysp()); + iterateAndNextNull(itemp->stmtsp()); hit = true; } } } } - virtual void visit(AstCaseItem* nodep) override { + void visit(AstCaseItem* nodep) override { // Real handling is in AstNodeCase if (jumpingOver(nodep)) return; checkNodeInfo(nodep); iterateChildren(nodep); } - virtual void visit(AstComment*) override {} + void visit(AstComment*) override {} - virtual void visit(AstJumpBlock* nodep) override { + void visit(AstJumpBlock* nodep) override { if (jumpingOver(nodep)) return; iterateChildren(nodep); } - virtual void visit(AstJumpGo* nodep) override { + void visit(AstJumpGo* nodep) override { if (jumpingOver(nodep)) return; checkNodeInfo(nodep); if (!m_checkOnly) { @@ -875,7 +875,7 @@ private: m_jumpp = nodep; } } - virtual void visit(AstJumpLabel* nodep) override { + void visit(AstJumpLabel* nodep) override { // This only supports forward jumps. That's all we make at present, // AstJumpGo::broken uses brokeExistsBelow() to check this. if (jumpingOver(nodep)) return; @@ -886,7 +886,7 @@ private: m_jumpp = nullptr; } } - virtual void visit(AstStop* nodep) override { + void visit(AstStop* nodep) override { if (jumpingOver(nodep)) return; if (m_params) { // This message seems better than an obscure $stop // The spec says $stop is just ignored, it seems evil to ignore assertions @@ -897,7 +897,7 @@ private: checkNodeInfo(nodep); } - virtual void visit(AstNodeFor* nodep) override { + void visit(AstNodeFor* nodep) override { // Doing lots of Whiles is slow, so only for parameters UINFO(5, " FOR " << nodep << endl); if (!m_params) { @@ -917,7 +917,7 @@ private: if (!fetchConst(nodep->condp())->num().isNeqZero()) { // break; } - iterateAndNextNull(nodep->bodysp()); + iterateAndNextNull(nodep->stmtsp()); iterateAndNextNull(nodep->incsp()); if (loops++ > unrollCount() * 16) { clearOptimizable(nodep, "Loop unrolling took too long; probably this is an" @@ -929,7 +929,7 @@ private: } } - virtual void visit(AstWhile* nodep) override { + void visit(AstWhile* nodep) override { // Doing lots of Whiles is slow, so only for parameters if (jumpingOver(nodep)) return; UINFO(5, " WHILE " << nodep << endl); @@ -952,7 +952,7 @@ private: if (!fetchConst(nodep->condp())->num().isNeqZero()) { // break; } - iterateAndNextNull(nodep->bodysp()); + iterateAndNextNull(nodep->stmtsp()); if (jumpingOver(nodep)) break; iterateAndNextNull(nodep->incsp()); if (jumpingOver(nodep)) break; @@ -969,7 +969,7 @@ private: } } - virtual void visit(AstFuncRef* nodep) override { + void visit(AstFuncRef* nodep) override { if (jumpingOver(nodep)) return; if (!optimizable()) return; // Accelerate UINFO(5, " FUNCREF " << nodep << endl); @@ -1022,8 +1022,8 @@ private: m_callStack.push_back(&stackNode); // Clear output variable if (const auto* const basicp = VN_CAST(funcp->fvarp(), Var)->basicp()) { - AstConst cnst(funcp->fvarp()->fileline(), AstConst::WidthedValue(), basicp->widthMin(), - 0); + AstConst cnst{funcp->fvarp()->fileline(), AstConst::WidthedValue{}, basicp->widthMin(), + 0}; if (basicp->isZeroInit()) { cnst.num().setAllBits0(); } else { @@ -1041,7 +1041,7 @@ private: } } - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { if (jumpingOver(nodep)) return; if (!m_params) { badNodeType(nodep); @@ -1049,12 +1049,12 @@ private: } } - virtual void visit(AstScopeName* nodep) override { + void visit(AstScopeName* nodep) override { if (jumpingOver(nodep)) return; // Ignore } - virtual void visit(AstSFormatF* nodep) override { + void visit(AstSFormatF* nodep) override { if (jumpingOver(nodep)) return; if (!optimizable()) return; // Accelerate checkNodeInfo(nodep); @@ -1108,7 +1108,7 @@ private: } } - virtual void visit(AstDisplay* nodep) override { + void visit(AstDisplay* nodep) override { if (jumpingOver(nodep)) return; if (!optimizable()) return; // Accelerate // We ignore isPredictOptimizable as $display is often in constant @@ -1133,7 +1133,7 @@ private: // These types are definitely not reducible // AstCoverInc, AstFinish, // AstRand, AstTime, AstUCFunc, AstCCall, AstCStmt, AstUCStmt - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { if (jumpingOver(nodep)) return; badNodeType(nodep); } @@ -1188,7 +1188,7 @@ public: setMode(false /*scoped*/, false /*checking*/, true /*params*/); mainGuts(nodep); } - virtual ~SimulateVisitor() override { + ~SimulateVisitor() override { for (const auto& pair : m_constps) { for (AstConst* const constp : pair.second) { delete constp; } } diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp index 94a70fe99..57cca7785 100644 --- a/src/V3Slice.cpp +++ b/src/V3Slice.cpp @@ -43,6 +43,8 @@ #include "V3Ast.h" #include "V3Global.h" +VL_DEFINE_DEBUG_FUNCTIONS; + //************************************************************************* class SliceVisitor final : public VNVisitor { @@ -58,8 +60,6 @@ class SliceVisitor final : public VNVisitor { bool m_assignError = false; // True if the current assign already has an error // METHODS - VL_DEBUG_FUNC; // Declare debug() - AstNode* cloneAndSel(AstNode* nodep, int elements, int offset) { // Insert an ArraySel, except for a few special cases const AstUnpackArrayDType* const arrayp @@ -101,8 +101,8 @@ class SliceVisitor final : public VNVisitor { } else if (AstNodeCond* const snodep = VN_CAST(nodep, NodeCond)) { UINFO(9, " cloneCond(" << elements << "," << offset << ") " << nodep << endl); return snodep->cloneType(snodep->condp()->cloneTree(false), - cloneAndSel(snodep->expr1p(), elements, offset), - cloneAndSel(snodep->expr2p(), elements, offset)); + cloneAndSel(snodep->thenp(), elements, offset), + cloneAndSel(snodep->elsep(), elements, offset)); } else if (const AstSliceSel* const snodep = VN_CAST(nodep, SliceSel)) { UINFO(9, " cloneSliceSel(" << elements << "," << offset << ") " << nodep << endl); const int leOffset = (snodep->declRange().lo() @@ -128,7 +128,7 @@ class SliceVisitor final : public VNVisitor { return newp; } - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { // Called recursively on newly created assignments if (!nodep->user1() && !VN_IS(nodep, AssignAlias)) { nodep->user1(true); @@ -139,14 +139,15 @@ class SliceVisitor final : public VNVisitor { // Left and right could have different msb/lsbs/endianness, but #elements is common // and all variables are realigned to start at zero // Assign of a little endian'ed slice to a big endian one must reverse the elements - AstNode* newlistp = nullptr; + AstNodeAssign* newlistp = nullptr; const int elements = arrayp->rangep()->elementsConst(); for (int offset = 0; offset < elements; ++offset) { - AstNode* const newp = nodep->cloneType // AstNodeAssign - (cloneAndSel(nodep->lhsp(), elements, offset), - cloneAndSel(nodep->rhsp(), elements, offset)); + AstNodeAssign* const newp + = VN_AS(nodep->cloneType(cloneAndSel(nodep->lhsp(), elements, offset), + cloneAndSel(nodep->rhsp(), elements, offset)), + NodeAssign); if (debug() >= 9) newp->dumpTree(cout, "-new "); - newlistp = AstNode::addNextNull(newlistp, newp); + newlistp = AstNode::addNext(newlistp, newp); } if (debug() >= 9) nodep->dumpTree(cout, " Deslice-Dn: "); nodep->replaceWith(newlistp); @@ -161,7 +162,7 @@ class SliceVisitor final : public VNVisitor { } } - virtual void visit(AstInitArray* nodep) override { + void visit(AstInitArray* nodep) override { UASSERT_OBJ(!m_assignp, nodep, "Array initialization should have been removed earlier"); } @@ -220,17 +221,17 @@ class SliceVisitor final : public VNVisitor { iterateChildren(nodep); } } - virtual void visit(AstEq* nodep) override { expandBiOp(nodep); } - virtual void visit(AstNeq* nodep) override { expandBiOp(nodep); } - virtual void visit(AstEqCase* nodep) override { expandBiOp(nodep); } - virtual void visit(AstNeqCase* nodep) override { expandBiOp(nodep); } + void visit(AstEq* nodep) override { expandBiOp(nodep); } + void visit(AstNeq* nodep) override { expandBiOp(nodep); } + void visit(AstEqCase* nodep) override { expandBiOp(nodep); } + void visit(AstNeqCase* nodep) override { expandBiOp(nodep); } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit SliceVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~SliceVisitor() override = default; + ~SliceVisitor() override = default; }; //###################################################################### @@ -239,5 +240,5 @@ public: void V3Slice::sliceAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { SliceVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("slice", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("slice", 0, dumpTree() >= 3); } diff --git a/src/V3Split.cpp b/src/V3Split.cpp index 83dc6ac5b..e6521ea69 100644 --- a/src/V3Split.cpp +++ b/src/V3Split.cpp @@ -93,6 +93,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Support classes @@ -103,14 +105,12 @@ protected: SplitNodeVertex(V3Graph* graphp, AstNode* nodep) : V3GraphVertex{graphp} , m_nodep{nodep} {} - virtual ~SplitNodeVertex() override = default; + ~SplitNodeVertex() override = default; // ACCESSORS // Do not make accessor for nodep(), It may change due to // reordering a lower block, but we don't repair it - virtual string name() const override { - return cvtToHex(m_nodep) + ' ' + m_nodep->prettyTypeName(); - } - virtual FileLine* fileline() const override { return nodep()->fileline(); } + string name() const override { return cvtToHex(m_nodep) + ' ' + m_nodep->prettyTypeName(); } + FileLine* fileline() const override { return nodep()->fileline(); } public: virtual AstNode* nodep() const { return m_nodep; } @@ -120,34 +120,34 @@ class SplitPliVertex final : public SplitNodeVertex { public: explicit SplitPliVertex(V3Graph* graphp, AstNode* nodep) : SplitNodeVertex{graphp, nodep} {} - virtual ~SplitPliVertex() override = default; - virtual string name() const override { return "*PLI*"; } - virtual string dotColor() const override { return "green"; } + ~SplitPliVertex() override = default; + string name() const override { return "*PLI*"; } + string dotColor() const override { return "green"; } }; class SplitLogicVertex final : public SplitNodeVertex { public: SplitLogicVertex(V3Graph* graphp, AstNode* nodep) : SplitNodeVertex{graphp, nodep} {} - virtual ~SplitLogicVertex() override = default; - virtual string dotColor() const override { return "yellow"; } + ~SplitLogicVertex() override = default; + string dotColor() const override { return "yellow"; } }; class SplitVarStdVertex final : public SplitNodeVertex { public: SplitVarStdVertex(V3Graph* graphp, AstNode* nodep) : SplitNodeVertex{graphp, nodep} {} - virtual ~SplitVarStdVertex() override = default; - virtual string dotColor() const override { return "skyblue"; } + ~SplitVarStdVertex() override = default; + string dotColor() const override { return "skyblue"; } }; class SplitVarPostVertex final : public SplitNodeVertex { public: SplitVarPostVertex(V3Graph* graphp, AstNode* nodep) : SplitNodeVertex{graphp, nodep} {} - virtual ~SplitVarPostVertex() override = default; - virtual string name() const override { return string("POST ") + SplitNodeVertex::name(); } - virtual string dotColor() const override { return "CadetBlue"; } + ~SplitVarPostVertex() override = default; + string name() const override { return string("POST ") + SplitNodeVertex::name(); } + string dotColor() const override { return "CadetBlue"; } }; //###################################################################### @@ -161,7 +161,7 @@ protected: SplitEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, bool cutable = CUTABLE) : V3GraphEdge{graphp, fromp, top, weight, cutable} {} - virtual ~SplitEdge() override = default; + ~SplitEdge() override = default; public: // Iterator for graph functions @@ -180,7 +180,7 @@ public: if (!oedgep) v3fatalSrc("Following edge of non-SplitEdge type"); return (!oedgep->ignoreThisStep()); } - virtual string dotStyle() const override { + string dotStyle() const override { return ignoreThisStep() ? "dotted" : V3GraphEdge::dotStyle(); } }; @@ -190,36 +190,36 @@ class SplitPostEdge final : public SplitEdge { public: SplitPostEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) : SplitEdge{graphp, fromp, top, WEIGHT_NORMAL} {} - virtual ~SplitPostEdge() override = default; - virtual bool followScoreboard() const override { return false; } - virtual string dotColor() const override { return "khaki"; } + ~SplitPostEdge() override = default; + bool followScoreboard() const override { return false; } + string dotColor() const override { return "khaki"; } }; class SplitLVEdge final : public SplitEdge { public: SplitLVEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) : SplitEdge{graphp, fromp, top, WEIGHT_NORMAL} {} - virtual ~SplitLVEdge() override = default; - virtual bool followScoreboard() const override { return true; } - virtual string dotColor() const override { return "yellowGreen"; } + ~SplitLVEdge() override = default; + bool followScoreboard() const override { return true; } + string dotColor() const override { return "yellowGreen"; } }; class SplitRVEdge final : public SplitEdge { public: SplitRVEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) : SplitEdge{graphp, fromp, top, WEIGHT_NORMAL} {} - virtual ~SplitRVEdge() override = default; - virtual bool followScoreboard() const override { return true; } - virtual string dotColor() const override { return "green"; } + ~SplitRVEdge() override = default; + bool followScoreboard() const override { return true; } + string dotColor() const override { return "green"; } }; struct SplitScorebdEdge : public SplitEdge { public: SplitScorebdEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) : SplitEdge{graphp, fromp, top, WEIGHT_NORMAL} {} - virtual ~SplitScorebdEdge() override = default; - virtual bool followScoreboard() const override { return true; } - virtual string dotColor() const override { return "blue"; } + ~SplitScorebdEdge() override = default; + bool followScoreboard() const override { return true; } + string dotColor() const override { return "blue"; } }; struct SplitStrictEdge : public SplitEdge { @@ -228,9 +228,9 @@ struct SplitStrictEdge : public SplitEdge { public: SplitStrictEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) : SplitEdge{graphp, fromp, top, WEIGHT_NORMAL, NOT_CUTABLE} {} - virtual ~SplitStrictEdge() override = default; - virtual bool followScoreboard() const override { return true; } - virtual string dotColor() const override { return "blue"; } + ~SplitStrictEdge() override = default; + bool followScoreboard() const override { return true; } + string dotColor() const override { return "blue"; } }; //###################################################################### @@ -259,12 +259,10 @@ protected: // CONSTRUCTORS public: SplitReorderBaseVisitor() { scoreboardClear(); } - virtual ~SplitReorderBaseVisitor() override = default; + ~SplitReorderBaseVisitor() override = default; // METHODS protected: - VL_DEBUG_FUNC; // Declare debug() - void scoreboardClear() { // VV***** We reset user1p() and user2p on each block!!! m_inDly = false; @@ -335,19 +333,19 @@ protected: virtual void makeRvalueEdges(SplitVarStdVertex* vstdp) = 0; // VISITORS - virtual void visit(AstAlways* nodep) override = 0; - virtual void visit(AstNodeIf* nodep) override = 0; + void visit(AstAlways* nodep) override = 0; + void visit(AstNodeIf* nodep) override = 0; // We don't do AstNodeFor/AstWhile loops, due to the standard question // of what is before vs. after - virtual void visit(AstAssignDly* nodep) override { + void visit(AstAssignDly* nodep) override { m_inDly = true; UINFO(4, " ASSIGNDLY " << nodep << endl); iterateChildren(nodep); m_inDly = false; } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { if (!m_stmtStackps.empty()) { AstVarScope* const vscp = nodep->varScopep(); UASSERT_OBJ(vscp, nodep, "Not linked"); @@ -410,7 +408,7 @@ protected: } } - virtual void visit(AstJumpGo* nodep) override { + void visit(AstJumpGo* nodep) override { // Jumps will disable reordering at all levels // This is overly pessimistic; we could treat jumps as barriers, and // reorder everything between jumps/labels, however jumps are rare @@ -422,7 +420,7 @@ protected: //-------------------- // Default - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { // **** SPECIAL default type that sets PLI_ORDERING if (!m_stmtStackps.empty() && !nodep->isPure()) { UINFO(9, " NotSplittable " << nodep << endl); @@ -439,11 +437,11 @@ class ReorderVisitor final : public SplitReorderBaseVisitor { // CONSTRUCTORS public: explicit ReorderVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~ReorderVisitor() override = default; + ~ReorderVisitor() override = default; // METHODS protected: - virtual void makeRvalueEdges(SplitVarStdVertex* vstdp) override { + void makeRvalueEdges(SplitVarStdVertex* vstdp) override { for (SplitLogicVertex* vxp : m_stmtStackps) new SplitRVEdge(&m_graph, vxp, vstdp); } @@ -452,10 +450,7 @@ protected: UINFO(5, "ReorderBlock " << nodep << endl); m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue); - if (debug() >= 9) { - m_graph.dumpDotFilePrefixed("reorderg_nodup", false); - // m_graph.dump(); cout<= 9) m_graph.dumpDotFilePrefixed("reorderg_nodup", false); // Mark all the logic for this step // Vertex::m_user begin: true indicates logic for this step @@ -512,10 +507,10 @@ protected: // And a real ordering to get the statements into something reasonable // We don't care if there's cutable violations here... // Non-cutable violations should be impossible; as those edges are program-order - if (debug() >= 9) m_graph.dumpDotFilePrefixed(string("splitg_preo"), false); + if (dumpGraph() >= 9) m_graph.dumpDotFilePrefixed(string("splitg_preo"), false); m_graph.acyclic(&SplitEdge::followCyclic); m_graph.rank(&SplitEdge::followCyclic); // Or order(), but that's more expensive - if (debug() >= 9) m_graph.dumpDotFilePrefixed(string("splitg_opt"), false); + if (dumpGraph() >= 9) m_graph.dumpDotFilePrefixed(string("splitg_opt"), false); } void reorderBlock(AstNode* nodep) { @@ -599,18 +594,18 @@ protected: firstp->user3p(oldBlockUser3); } - virtual void visit(AstAlways* nodep) override { + void visit(AstAlways* nodep) override { UINFO(4, " ALW " << nodep << endl); if (debug() >= 9) nodep->dumpTree(cout, " alwIn:: "); scoreboardClear(); - processBlock(nodep->bodysp()); + processBlock(nodep->stmtsp()); if (debug() >= 9) nodep->dumpTree(cout, " alwOut: "); } - virtual void visit(AstNodeIf* nodep) override { + void visit(AstNodeIf* nodep) override { UINFO(4, " IF " << nodep << endl); iterateAndNextNull(nodep->condp()); - processBlock(nodep->ifsp()); + processBlock(nodep->thensp()); processBlock(nodep->elsesp()); } @@ -636,7 +631,7 @@ public: // Visit through *nodep and map each AstNodeIf within to the set of // colors it will participate in. Also find the whole set of colors. explicit IfColorVisitor(AstAlways* nodep) { iterate(nodep); } - virtual ~IfColorVisitor() override = default; + ~IfColorVisitor() override = default; // METHODS const ColorSet& colors() const { return m_colors; } @@ -663,18 +658,17 @@ private: } protected: - virtual void visit(AstNodeIf* nodep) override { + void visit(AstNodeIf* nodep) override { m_ifStack.push_back(nodep); trackNode(nodep); iterateChildren(nodep); m_ifStack.pop_back(); } - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { trackNode(nodep); iterateChildren(nodep); } - VL_DEBUG_FUNC; // Declare debug() private: VL_UNCOPYABLE(IfColorVisitor); }; @@ -701,7 +695,7 @@ public: UINFO(6, " splitting always " << nodep << endl); } - virtual ~EmitSplitVisitor() override = default; + ~EmitSplitVisitor() override = default; // METHODS void go() { @@ -715,24 +709,22 @@ public: // Put a placeholder node into stmtp to track our position. // We'll strip these out after the blocks are fully cloned. AstSplitPlaceholder* const placeholderp = makePlaceholderp(); - alwaysp->addStmtp(placeholderp); + alwaysp->addStmtsp(placeholderp); m_addAfter[color] = placeholderp; m_newBlocksp->push_back(alwaysp); } // Scan the body of the always. We'll handle if/else // specially, everything else is a leaf node that we can // just clone into one of the split always blocks. - iterateAndNextNull(m_origAlwaysp->bodysp()); + iterateAndNextNull(m_origAlwaysp->stmtsp()); } protected: - VL_DEBUG_FUNC; // Declare debug() - AstSplitPlaceholder* makePlaceholderp() { return new AstSplitPlaceholder(m_origAlwaysp->fileline()); } - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { // Anything that's not an if/else we assume is a leaf // (that is, something we won't split.) Don't visit further // into the leaf. @@ -754,7 +746,7 @@ protected: m_addAfter[color] = clonedp; } - virtual void visit(AstNodeIf* nodep) override { + void visit(AstNodeIf* nodep) override { const ColorSet& colors = m_ifColorp->colors(nodep); using CloneMap = std::unordered_map; CloneMap clones; @@ -778,7 +770,7 @@ protected: m_addAfter[color] = if_placeholderp; } - iterateAndNextNull(nodep->ifsp()); + iterateAndNextNull(nodep->thensp()); for (const auto& color : colors) m_addAfter[color] = clones[color]->elsesp(); @@ -798,23 +790,23 @@ class RemovePlaceholdersVisitor final : public VNVisitor { // CONSTRUCTORS RemovePlaceholdersVisitor() = default; - virtual ~RemovePlaceholdersVisitor() override = default; + ~RemovePlaceholdersVisitor() override = default; // VISITORS - virtual void visit(AstSplitPlaceholder* nodep) override { pushDeletep(nodep->unlinkFrBack()); } - virtual void visit(AstNodeIf* nodep) override { + void visit(AstSplitPlaceholder* nodep) override { pushDeletep(nodep->unlinkFrBack()); } + void visit(AstNodeIf* nodep) override { VL_RESTORER(m_isPure); m_isPure = true; iterateChildren(nodep); - if (!nodep->ifsp() && !nodep->elsesp() && m_isPure) pushDeletep(nodep->unlinkFrBack()); + if (!nodep->thensp() && !nodep->elsesp() && m_isPure) pushDeletep(nodep->unlinkFrBack()); } - virtual void visit(AstAlways* nodep) override { + void visit(AstAlways* nodep) override { VL_RESTORER(m_isPure); m_isPure = true; iterateChildren(nodep); if (m_isPure) { bool emptyOrCommentOnly = true; - for (AstNode* bodysp = nodep->bodysp(); bodysp; bodysp = bodysp->nextp()) { + for (AstNode* bodysp = nodep->stmtsp(); bodysp; bodysp = bodysp->nextp()) { // If this always block contains only AstComment, remove here. // V3Gate will remove anyway. if (!VN_IS(bodysp, Comment)) { @@ -828,7 +820,7 @@ class RemovePlaceholdersVisitor final : public VNVisitor { } } } - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { m_isPure &= nodep->isPure(); iterateChildren(nodep); // must visit regardless of m_isPure to remove placeholders } @@ -875,13 +867,11 @@ public: } } - virtual ~SplitVisitor() override { - V3Stats::addStat("Optimizations, Split always", m_statSplits); - } + ~SplitVisitor() override { V3Stats::addStat("Optimizations, Split always", m_statSplits); } // METHODS protected: - virtual void makeRvalueEdges(SplitVarStdVertex* vstdp) override { + void makeRvalueEdges(SplitVarStdVertex* vstdp) override { // Each 'if' depends on rvalues in its own conditional ONLY, // not rvalues in the if/else bodies. for (auto it = m_stmtStackps.cbegin(); it != m_stmtStackps.cend(); ++it) { @@ -946,20 +936,20 @@ protected: } } - if (debug() >= 9) m_graph.dumpDotFilePrefixed("splitg_nodup", false); + if (dumpGraph() >= 9) m_graph.dumpDotFilePrefixed("splitg_nodup", false); // Weak coloring to determine what needs to remain grouped // in a single always. This follows all edges excluding: // - those we pruned above // - PostEdges, which are done later m_graph.weaklyConnected(&SplitEdge::followScoreboard); - if (debug() >= 9) m_graph.dumpDotFilePrefixed("splitg_colored", false); + if (dumpGraph() >= 9) m_graph.dumpDotFilePrefixed("splitg_colored", false); } - virtual void visit(AstAlways* nodep) override { + void visit(AstAlways* nodep) override { // build the scoreboard scoreboardClear(); - scanBlock(nodep->bodysp()); + scanBlock(nodep->stmtsp()); if (m_noReorderWhy != "") { // We saw a jump or something else rare that we don't handle. @@ -988,12 +978,12 @@ protected: emitSplit.go(); } } - virtual void visit(AstNodeIf* nodep) override { + void visit(AstNodeIf* nodep) override { UINFO(4, " IF " << nodep << endl); m_curIfConditional = nodep; iterateAndNextNull(nodep->condp()); m_curIfConditional = nullptr; - scanBlock(nodep->ifsp()); + scanBlock(nodep->thensp()); scanBlock(nodep->elsesp()); } @@ -1007,10 +997,10 @@ private: void V3Split::splitReorderAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { ReorderVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("reorder", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("reorder", 0, dumpTree() >= 3); } void V3Split::splitAlwaysAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { SplitVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("split", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("split", 0, dumpTree() >= 3); } diff --git a/src/V3SplitAs.cpp b/src/V3SplitAs.cpp index ebdac1d7a..1d7b4d86d 100644 --- a/src/V3SplitAs.cpp +++ b/src/V3SplitAs.cpp @@ -32,12 +32,13 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### class SplitAsBaseVisitor VL_NOT_FINAL : public VNVisitor { public: // METHODS - VL_DEBUG_FUNC; // Declare debug() }; //###################################################################### @@ -49,17 +50,17 @@ private: AstVarScope* m_splitVscp = nullptr; // Variable we want to split // METHODS - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { if (nodep->access().isWriteOrRW() && !m_splitVscp && nodep->varp()->attrIsolateAssign()) { m_splitVscp = nodep->varScopep(); } } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit SplitAsFindVisitor(AstAlways* nodep) { iterate(nodep); } - virtual ~SplitAsFindVisitor() override = default; + ~SplitAsFindVisitor() override = default; // METHODS AstVarScope* splitVscp() const { return m_splitVscp; } }; @@ -76,7 +77,7 @@ private: bool m_matches = false; // Statement below has matching lvalue reference // METHODS - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { if (nodep->access().isWriteOrRW()) { if (nodep->varScopep() == m_splitVscp) { UINFO(6, " CL VAR " << nodep << endl); @@ -84,7 +85,7 @@ private: } } } - virtual void visit(AstNodeStmt* nodep) override { + void visit(AstNodeStmt* nodep) override { if (!nodep->isStatement()) { iterateChildren(nodep); return; @@ -110,7 +111,7 @@ private: m_keepStmt = oldKeep || m_keepStmt; UINFO(9, " upKeep=" << m_keepStmt << " STMT " << nodep << endl); } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -119,7 +120,7 @@ public: , m_modeMatch{modeMatch} { iterate(nodep); } - virtual ~SplitAsCleanVisitor() override = default; + ~SplitAsCleanVisitor() override = default; }; //###################################################################### @@ -154,7 +155,7 @@ private: } } - virtual void visit(AstAlways* nodep) override { + void visit(AstAlways* nodep) override { // Are there any lvalue references below this? // There could be more than one. So, we process the first one found first. const AstVarScope* lastSplitVscp = nullptr; @@ -179,13 +180,13 @@ private: } // Speedup; no always under math - virtual void visit(AstNodeMath*) override {} - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNodeMath*) override {} + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit SplitAsVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~SplitAsVisitor() override { + ~SplitAsVisitor() override { V3Stats::addStat("Optimizations, isolate_assignments blocks", m_statSplits); } }; @@ -196,5 +197,5 @@ public: void V3SplitAs::splitAsAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { SplitAsVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("splitas", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("splitas", 0, dumpTree() >= 3); } diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index 7ca9464d0..7b82c3f46 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -125,6 +125,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + struct SplitVarImpl { // NODE STATE // AstNodeModule::user1() -> Block number counter for generating unique names @@ -191,16 +193,16 @@ struct SplitVarImpl { template void insertBeginCore(T_ALWAYSLIKE* ap, AstNodeStmt* stmtp, AstNodeModule* modp) { - if (ap->isJustOneBodyStmt() && ap->bodysp() == stmtp) { + if (ap->isJustOneBodyStmt() && ap->stmtsp() == stmtp) { stmtp->unlinkFrBack(); // Insert begin-end because temp value may be inserted to this block later. const std::string name = "__VsplitVarBlk" + cvtToStr(modp->user1Inc(1)); - ap->addStmtp(new AstBegin{ap->fileline(), name, stmtp}); + ap->addStmtsp(new AstBegin{ap->fileline(), name, stmtp}); } } void insertBeginCore(AstInitial* initp, AstNodeStmt* stmtp, AstNodeModule* modp) { - if (initp->isJustOneBodyStmt() && initp->bodysp() == stmtp) { + if (initp->isJustOneBodyStmt() && initp->stmtsp() == stmtp) { stmtp->unlinkFrBack(); // Insert begin-end because temp value may be inserted to this block later. FileLine* const fl = initp->fileline(); @@ -362,10 +364,10 @@ public: void remove(AstNode* nodep) { struct Visitor : public VNVisitor { RefsInModule& m_parent; - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } - virtual void visit(AstVar* nodep) override { m_parent.m_vars.erase(nodep); } - virtual void visit(AstVarRef* nodep) override { m_parent.m_refs.erase(nodep); } - virtual void visit(AstSel* nodep) override { + void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstVar* nodep) override { m_parent.m_vars.erase(nodep); } + void visit(AstVarRef* nodep) override { m_parent.m_refs.erase(nodep); } + void visit(AstSel* nodep) override { m_parent.m_sels.erase(nodep); iterateChildren(nodep); } @@ -456,8 +458,8 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl { return refp; } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNodeModule* nodep) override { UINFO(4, "Start checking " << nodep->prettyNameQ() << "\n"); if (!VN_IS(nodep, Module)) { UINFO(4, "Skip " << nodep->prettyNameQ() << "\n"); @@ -471,25 +473,25 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl { split(); m_modp = nullptr; } - virtual void visit(AstNodeStmt* nodep) override { setContextAndIterateChildren(nodep); } - virtual void visit(AstCell* nodep) override { setContextAndIterateChildren(nodep); } - virtual void visit(AstAlways* nodep) override { + void visit(AstNodeStmt* nodep) override { setContextAndIterateChildren(nodep); } + void visit(AstCell* nodep) override { setContextAndIterateChildren(nodep); } + void visit(AstAlways* nodep) override { if (nodep->sensesp()) { // When visiting sensitivity list, always is the context setContextAndIterate(nodep, nodep->sensesp()); } - for (AstNode* bodysp = nodep->bodysp(); bodysp; bodysp = bodysp->nextp()) { + for (AstNode* bodysp = nodep->stmtsp(); bodysp; bodysp = bodysp->nextp()) { iterate(bodysp); } }; - virtual void visit(AstAlwaysPublic* nodep) override { + void visit(AstAlwaysPublic* nodep) override { if (nodep->sensesp()) { // When visiting sensitivity list, always is the context setContextAndIterate(nodep, nodep->sensesp()); } - for (AstNode* bodysp = nodep->bodysp(); bodysp; bodysp = bodysp->nextp()) { + for (AstNode* bodysp = nodep->stmtsp(); bodysp; bodysp = bodysp->nextp()) { iterate(bodysp); } } - virtual void visit(AstNodeFTaskRef* nodep) override { + void visit(AstNodeFTaskRef* nodep) override { VL_RESTORER(m_contextp); { m_contextp = nodep; @@ -524,7 +526,7 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl { } } } - virtual void visit(AstPin* nodep) override { + void visit(AstPin* nodep) override { UINFO(5, nodep->modVarp()->prettyNameQ() << " pin \n"); AstNode* const exprp = nodep->exprp(); if (!exprp) return; // Not connected pin @@ -538,7 +540,7 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl { m_foundTargetVar.clear(); } } - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstNodeFTask* nodep) override { UASSERT_OBJ(!m_inFTask, nodep, "Nested func/task"); if (!cannotSplitTaskReason(nodep)) { m_inFTask = nodep; @@ -546,7 +548,7 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl { m_inFTask = nullptr; } } - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { if (!nodep->attrSplitVar()) return; // Nothing to do if (!cannotSplitReason(nodep)) { m_refs.registerVar(nodep); @@ -554,18 +556,18 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl { } m_refsForPackedSplit[m_modp].add(nodep); } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { if (!nodep->varp()->attrSplitVar()) return; // Nothing to do if (m_refs.tryAdd(m_contextp, nodep, m_inFTask)) { m_foundTargetVar.insert(nodep->varp()); } m_refsForPackedSplit[m_modp].add(nodep); } - virtual void visit(AstSel* nodep) override { + void visit(AstSel* nodep) override { if (VN_IS(nodep->fromp(), VarRef)) m_refsForPackedSplit[m_modp].add(nodep); iterateChildren(nodep); } - virtual void visit(AstArraySel* nodep) override { + void visit(AstArraySel* nodep) override { if (AstVarRef* const refp = isTargetVref(nodep->fromp())) { const AstConst* const indexp = VN_CAST(nodep->bitp(), Const); if (indexp) { // OK @@ -585,7 +587,7 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl { iterateChildren(nodep); } } - virtual void visit(AstSliceSel* nodep) override { + void visit(AstSliceSel* nodep) override { if (AstVarRef* const refp = isTargetVref(nodep->fromp())) { const AstUnpackArrayDType* const dtypep = VN_AS(refp->varp()->dtypep()->skipRefp(), UnpackArrayDType); @@ -782,7 +784,6 @@ public: V3Stats::addStat("SplitVar, Split unpacked arrays", m_numSplit); } const SplitVarRefsMap& getPackedVarRefs() const { return m_refsForPackedSplit; } - VL_DEBUG_FUNC; // Declare debug() // Check if the passed variable can be split. // Even if this function returns true, the variable may not be split @@ -966,10 +967,10 @@ class SplitPackedVarVisitor final : public VNVisitor, public SplitVarImpl { int m_numSplit = 0; // Total number of split variables // key:variable to be split. value:location where the variable is referenced. std::map m_refs; - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstNodeFTask* nodep) override { if (!cannotSplitTaskReason(nodep)) iterateChildren(nodep); } - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { if (!nodep->attrSplitVar()) return; // Nothing to do if (const char* const reason = cannotSplitReason(nodep, true)) { warnNoSplit(nodep, nodep, reason); @@ -979,7 +980,7 @@ class SplitPackedVarVisitor final : public VNVisitor, public SplitVarImpl { if (inserted) UINFO(3, nodep->prettyNameQ() << " is added to candidate list.\n"); } } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { AstVar* const varp = nodep->varp(); visit(varp); const auto refit = m_refs.find(varp); @@ -993,7 +994,7 @@ class SplitPackedVarVisitor final : public VNVisitor, public SplitVarImpl { UINFO(5, varp->prettyName() << " Entire bit of [" << basicp->lo() << "+:" << varp->width() << "] \n"); } - virtual void visit(AstSel* nodep) override { + void visit(AstSel* nodep) override { const AstVarRef* const vrefp = VN_CAST(nodep->fromp(), VarRef); if (!vrefp) { iterateChildren(nodep); @@ -1032,7 +1033,7 @@ class SplitPackedVarVisitor final : public VNVisitor, public SplitVarImpl { iterateChildren(nodep); } } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } // Extract necessary bit range from a newly created variable to meet ref static AstNode* extractBits(const PackedVarRefEntry& ref, const SplitNewVar& var, @@ -1243,7 +1244,6 @@ public: } return reason; } - VL_DEBUG_FUNC; // Declare debug() }; const char* SplitVarImpl::cannotSplitPackedVarReason(const AstVar* varp) { @@ -1260,9 +1260,9 @@ void V3SplitVar::splitVariable(AstNetlist* nodep) { const SplitUnpackedVarVisitor visitor{nodep}; refs = visitor.getPackedVarRefs(); } - V3Global::dumpCheckGlobalTree("split_var", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 9); + V3Global::dumpCheckGlobalTree("split_var", 0, dumpTree() >= 9); { SplitPackedVarVisitor{nodep, refs}; } - V3Global::dumpCheckGlobalTree("split_var", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 9); + V3Global::dumpCheckGlobalTree("split_var", 0, dumpTree() >= 9); } bool V3SplitVar::canSplitVar(const AstVar* varp) { diff --git a/src/V3Stats.cpp b/src/V3Stats.cpp index 97d2514b8..bda08d003 100644 --- a/src/V3Stats.cpp +++ b/src/V3Stats.cpp @@ -28,6 +28,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Stats class functions @@ -61,7 +63,6 @@ private: VDouble0 m_statVarScpBytes; // Statistic tracking // METHODS - VL_DEBUG_FUNC; // Declare debug() void allNodes(AstNode* nodep) { m_instrs += nodep->instrCount(); @@ -76,7 +77,7 @@ private: } // VISITORS - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { allNodes(nodep); if (!m_fast) { // Count all CFuncs below this module @@ -85,7 +86,7 @@ private: // Else we recursively trace fast CFuncs from the top _eval // func, see visit(AstNetlist*) } - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { allNodes(nodep); iterateChildrenConst(nodep); if (m_counting && nodep->dtypep()) { @@ -111,7 +112,7 @@ private: } } } - virtual void visit(AstVarScope* nodep) override { + void visit(AstVarScope* nodep) override { allNodes(nodep); iterateChildrenConst(nodep); if (m_counting) { @@ -120,7 +121,7 @@ private: } } } - virtual void visit(AstNodeIf* nodep) override { + void visit(AstNodeIf* nodep) override { UINFO(4, " IF i=" << m_instrs << " " << nodep << endl); allNodes(nodep); // Condition is part of cost allocated to PREVIOUS block @@ -141,7 +142,7 @@ private: { m_counting = false; m_instrs = 0.0; - iterateAndNextConstNull(nodep->ifsp()); + iterateAndNextConstNull(nodep->thensp()); ifInstrs = m_instrs; } } @@ -158,7 +159,7 @@ private: // Now collect the stats if (m_counting) { if (ifInstrs >= elseInstrs) { - iterateAndNextConstNull(nodep->ifsp()); + iterateAndNextConstNull(nodep->thensp()); } else { iterateAndNextConstNull(nodep->elsesp()); } @@ -166,9 +167,9 @@ private: } } // While's we assume evaluate once. - // virtual void visit(AstWhile* nodep) override { + // void visit(AstWhile* nodep) override { - virtual void visit(AstNodeCCall* nodep) override { + void visit(AstNodeCCall* nodep) override { allNodes(nodep); iterateChildrenConst(nodep); if (m_fast && !nodep->funcp()->entryPoint()) { @@ -177,7 +178,7 @@ private: iterate(nodep->funcp()); } } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { if (m_fast) { if (!m_tracingCall && !nodep->entryPoint()) return; m_tracingCall = false; @@ -189,11 +190,11 @@ private: iterateChildrenConst(nodep); } } - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { allNodes(nodep); iterateChildrenConst(nodep); } - virtual void visit(AstNetlist* nodep) override { + void visit(AstNetlist* nodep) override { if (m_fast && nodep->evalp()) { m_instrs = 0; m_counting = true; @@ -219,7 +220,7 @@ public: // Process iterate(nodep); } - virtual ~StatsVisitor() override { + ~StatsVisitor() override { // Done. Publish statistics V3Stats::addStat(m_stage, "Instruction count, TOTAL", m_statInstr); V3Stats::addStat(m_stage, "Instruction count, fast critical", m_statInstrFast); @@ -231,7 +232,7 @@ public: V3Stats::addStat(m_stage, "Var space, scoped, bytes", m_statVarScpBytes); } for (unsigned i = 0; i < m_statVarWidths.size(); i++) { - const double count = double(m_statVarWidths.at(i)); + const double count{m_statVarWidths.at(i)}; if (count != 0.0) { if (v3Global.opt.statsVars()) { const NameMap& nameMapr = m_statVarWidthNames.at(i); @@ -249,7 +250,7 @@ public: } // Node types for (int type = 0; type < VNType::_ENUM_END; type++) { - const double count = double(m_statTypeCount.at(type)); + const double count{m_statTypeCount.at(type)}; if (count != 0.0) { V3Stats::addStat(m_stage, std::string{"Node count, "} + VNType{type}.ascii(), count); @@ -257,18 +258,18 @@ public: } for (int type = 0; type < VNType::_ENUM_END; type++) { for (int type2 = 0; type2 < VNType::_ENUM_END; type2++) { - const double count = double(m_statAbove[type][type2]); + const double count{m_statAbove[type][type2]}; if (count != 0.0) { V3Stats::addStat(m_stage, (std::string{"Node pairs, "} + VNType{type}.ascii() + "_" - + VNType(type2).ascii()), + + VNType{type2}.ascii()), count); } } } // Branch pred for (int type = 0; type < VBranchPred::_ENUM_END; type++) { - const double count = double(m_statPred[type]); + const double count{m_statPred[type]}; if (count != 0.0) { V3Stats::addStat(m_stage, (std::string{"Branch prediction, "} + VBranchPred{type}.ascii()), diff --git a/src/V3StatsReport.cpp b/src/V3StatsReport.cpp index ad12bd812..03be5d71c 100644 --- a/src/V3StatsReport.cpp +++ b/src/V3StatsReport.cpp @@ -27,6 +27,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Stats dumping @@ -44,6 +46,7 @@ class StatsReport final { os << "Information:\n"; os << " " << V3Options::version() << '\n'; os << " Arguments: " << v3Global.opt.allArgsString() << '\n'; + os << " Build jobs: " << v3Global.opt.buildJobs() << '\n'; os << '\n'; } diff --git a/src/V3StdFuture.h b/src/V3StdFuture.h new file mode 100644 index 000000000..32a4f7539 --- /dev/null +++ b/src/V3StdFuture.h @@ -0,0 +1,30 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Backports of features from future C++ versions +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2022 by Wilson Snyder. This program is free software; you +// can redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#ifndef VERILATOR_V3STDFUTURE_H_ +#define VERILATOR_V3STDFUTURE_H_ + +namespace vlstd { + +// constexpr std::max with arguments passed by value (required by constexpr before C++14) +template +constexpr T max(T a, T b) { + return a > b ? a : b; +} + +}; // namespace vlstd + +#endif // Guard diff --git a/src/V3String.cpp b/src/V3String.cpp index 9d20bd078..6f4aa473b 100644 --- a/src/V3String.cpp +++ b/src/V3String.cpp @@ -17,10 +17,15 @@ #include "config_build.h" #include "verilatedos.h" -// Limited V3 headers here - this is a base class for Vlc etc -#include "V3Error.h" #include "V3String.h" +#include "V3Error.h" + +#ifndef V3ERROR_NO_GLOBAL_ +#include "V3Global.h" +VL_DEFINE_DEBUG_FUNCTIONS; +#endif + #include size_t VName::s_minLength = 32; @@ -31,7 +36,7 @@ std::map VName::s_dehashMap; // Wildcard // Double procedures, inlined, unrolls loop much better -inline bool VString::wildmatchi(const char* s, const char* p) { +bool VString::wildmatchi(const char* s, const char* p) { for (; *p; s++, p++) { if (*p != '*') { if (((*s) != (*p)) && *p != '?') return false; @@ -150,7 +155,7 @@ double VString::parseDouble(const string& str, bool* successp) { char* endp = strgp; const double d = strtod(strgp, &endp); const size_t parsed_len = endp - strgp; - if (parsed_len != strlen(strgp)) { + if (parsed_len != std::strlen(strgp)) { if (successp) *successp = false; } VL_DO_DANGLING(delete[] strgp, strgp); @@ -193,13 +198,11 @@ static const uint32_t sha256K[] 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; -static inline uint32_t shaRotr32(uint32_t lhs, uint32_t rhs) VL_ATTR_ALWINLINE; -static inline uint32_t shaRotr32(uint32_t lhs, uint32_t rhs) { - return lhs >> rhs | lhs << (32 - rhs); -} +VL_ATTR_ALWINLINE +static uint32_t shaRotr32(uint32_t lhs, uint32_t rhs) { return lhs >> rhs | lhs << (32 - rhs); } -static inline void sha256Block(uint32_t* h, const uint32_t* chunk) VL_ATTR_ALWINLINE; -static inline void sha256Block(uint32_t* h, const uint32_t* chunk) { +VL_ATTR_ALWINLINE +static void sha256Block(uint32_t* h, const uint32_t* chunk) { uint32_t ah[8]; const uint32_t* p = chunk; @@ -402,7 +405,7 @@ void VHashSha256::selfTest() { string VName::dehash(const string& in) { static const char VHSH[] = "__Vhsh"; - static const size_t DOT_LEN = strlen("__DOT__"); + static const size_t DOT_LEN = std::strlen("__DOT__"); std::string dehashed; // Need to split 'in' into components separated by __DOT__, 'last_dot_pos' diff --git a/src/V3Subst.cpp b/src/V3Subst.cpp index ef7562ac5..60a664786 100644 --- a/src/V3Subst.cpp +++ b/src/V3Subst.cpp @@ -34,13 +34,7 @@ #include #include -//###################################################################### -// Common debugging baseclass - -class SubstBaseVisitor VL_NOT_FINAL : public VNVisitor { -public: - VL_DEBUG_FUNC; // Declare debug() -}; +VL_DEFINE_DEBUG_FUNCTIONS; //###################################################################### // Class for each word of a multi-word variable @@ -72,7 +66,6 @@ class SubstVarEntry final { bool m_wordUse = false; // True if any individual word usage SubstVarWord m_whole; // Data for whole vector used at once std::vector m_words; // Data for every word, if multi word variable - static int debug() { return SubstBaseVisitor::debug(); } public: // CONSTRUCTORS @@ -175,7 +168,7 @@ public: // See if any variables have changed value since we determined subst value, // as a visitor of each AstNode -class SubstUseVisitor final : public SubstBaseVisitor { +class SubstUseVisitor final : public VNVisitor { private: // NODE STATE // See SubstVisitor @@ -189,7 +182,7 @@ private: return reinterpret_cast(nodep->varp()->user1p()); // Might be nullptr } // VISITORS - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { const SubstVarEntry* const entryp = findEntryp(nodep); if (entryp) { // Don't sweat it. We assign a new temp variable for every new assignment, @@ -204,8 +197,8 @@ private: } } } - virtual void visit(AstConst*) override {} // Accelerate - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstConst*) override {} // Accelerate + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -214,7 +207,7 @@ public: UINFO(9, " SubstUseVisitor " << origStep << " " << nodep << endl); iterate(nodep); } - virtual ~SubstUseVisitor() override = default; + ~SubstUseVisitor() override = default; // METHODS bool ok() const { return m_ok; } }; @@ -222,7 +215,7 @@ public: //###################################################################### // Subst state, as a visitor of each AstNode -class SubstVisitor final : public SubstBaseVisitor { +class SubstVisitor final : public VNVisitor { private: // NODE STATE // Passed to SubstUseVisitor @@ -255,10 +248,10 @@ private: return entryp; } } - inline bool isSubstVar(AstVar* nodep) { return nodep->isStatementTemp() && !nodep->noSubst(); } + bool isSubstVar(AstVar* nodep) { return nodep->isStatementTemp() && !nodep->noSubst(); } // VISITORS - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { m_ops = 0; m_assignStep++; iterateAndNextNull(nodep->rhsp()); @@ -304,7 +297,7 @@ private: VL_DO_DANGLING(pushDeletep(nodep), nodep); ++m_statSubsts; } - virtual void visit(AstWordSel* nodep) override { + void visit(AstWordSel* nodep) override { iterate(nodep->rhsp()); AstVarRef* const varrefp = VN_CAST(nodep->lhsp(), VarRef); const AstConst* const constp = VN_CAST(nodep->rhsp(), Const); @@ -329,7 +322,7 @@ private: iterate(nodep->lhsp()); } } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { // Any variable if (nodep->access().isWriteOrRW()) { m_assignStep++; @@ -357,9 +350,16 @@ private: } } } - virtual void visit(AstVar*) override {} - virtual void visit(AstConst*) override {} - virtual void visit(AstNode* nodep) override { + void visit(AstVar*) override {} + void visit(AstConst*) override {} + void visit(AstModule* nodep) override { + ++m_ops; + if (!nodep->isSubstOptimizable()) m_ops = SUBST_MAX_OPS_NA; + iterateChildren(nodep); + // Reduce peak memory usage by reclaiming the edited AstNodes + doDeletes(); + } + void visit(AstNode* nodep) override { m_ops++; if (!nodep->isSubstOptimizable()) m_ops = SUBST_MAX_OPS_NA; iterateChildren(nodep); @@ -368,7 +368,7 @@ private: public: // CONSTRUCTORS explicit SubstVisitor(AstNode* nodep) { iterate(nodep); } - virtual ~SubstVisitor() override { + ~SubstVisitor() override { V3Stats::addStat("Optimizations, Substituted temps", m_statSubsts); for (SubstVarEntry* ip : m_entryps) { ip->deleteUnusedAssign(); @@ -383,5 +383,5 @@ public: void V3Subst::substituteAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { SubstVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("subst", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("subst", 0, dumpTree() >= 3); } diff --git a/src/V3SymTable.h b/src/V3SymTable.h index c1607f5f4..879c898e9 100644 --- a/src/V3SymTable.h +++ b/src/V3SymTable.h @@ -53,11 +53,7 @@ class VSymEnt final { bool m_exported; // Allow importing bool m_imported; // Was imported #ifdef VL_DEBUG - static int debug() { - static int level = -1; - if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel("V3LinkDot.cpp"); - return level; - } + VL_DEFINE_DEBUG_FUNCTIONS; #else static constexpr int debug() { return 0; } // NOT runtime, too hot of a function #endif @@ -88,7 +84,7 @@ public: } } } - void dump(std::ostream& os, const string& indent = "", int numLevels = 1) const { + void dumpSelf(std::ostream& os, const string& indent = "", int numLevels = 1) const { VSymConstMap doneSyms; dumpIterate(os, doneSyms, indent, numLevels, "TOP"); } @@ -127,7 +123,7 @@ public: << " " << entp->nodep() << endl); if (name != "" && m_idNameMap.find(name) != m_idNameMap.end()) { if (!V3Error::errorCount()) { // Else may have just reported warning - if (debug() >= 9 || V3Error::debugDefault()) dump(cout, "- err-dump: ", 1); + if (debug() >= 9 || V3Error::debugDefault()) dumpSelf(cout, "- err-dump: ", 1); entp->nodep()->v3fatalSrc("Inserting two symbols with same name: " << name); } } else { @@ -272,7 +268,7 @@ public: if (scopes == "") scopes = ""; std::cerr << V3Error::warnMore() << "... Known scopes under '" << prettyName << "': " << scopes << endl; - if (debug()) dump(std::cerr, " KnownScope: ", 1); + if (debug()) dumpSelf(std::cerr, " KnownScope: ", 1); } }; @@ -291,6 +287,8 @@ class VSymGraph final { // CONSTRUCTORS VL_UNCOPYABLE(VSymGraph); + VL_DEFINE_DEBUG_FUNCTIONS; + public: explicit VSymGraph(AstNetlist* nodep) { m_symRootp = new VSymEnt(this, nodep); } ~VSymGraph() { @@ -300,7 +298,7 @@ public: // METHODS VSymEnt* rootp() const { return m_symRootp; } // Debug - void dump(std::ostream& os, const string& indent = "") { + void dumpSelf(std::ostream& os, const string& indent = "") { VSymConstMap doneSyms; os << "SymEnt Dump:\n"; m_symRootp->dumpIterate(os, doneSyms, indent, 9999, "$root"); @@ -316,12 +314,12 @@ public: } } void dumpFilePrefixed(const string& nameComment) { - if (v3Global.opt.dumpTree()) { + if (dumpTree()) { const string filename = v3Global.debugFilename(nameComment) + ".txt"; UINFO(2, "Dumping " << filename << endl); const std::unique_ptr logp{V3File::new_ofstream(filename)}; if (logp->fail()) v3fatal("Can't write " << filename); - dump(*logp, ""); + dumpSelf(*logp, ""); } } diff --git a/src/V3TSP.cpp b/src/V3TSP.cpp index 27d877369..0e488ca45 100644 --- a/src/V3TSP.cpp +++ b/src/V3TSP.cpp @@ -39,6 +39,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Support classes @@ -47,8 +49,6 @@ static uint32_t edgeIdNext = 0; static void selfTestStates(); static void selfTestString(); - -VL_DEBUG_FUNC; // Declare debug() } // namespace V3TSP // Vertex that tracks a per-vertex key @@ -61,7 +61,7 @@ public: TspVertexTmpl(V3Graph* graphp, const T_Key& k) : V3GraphVertex{graphp} , m_key{k} {} - virtual ~TspVertexTmpl() override = default; + ~TspVertexTmpl() override = default; const T_Key& key() const { return m_key; } private: @@ -84,7 +84,7 @@ public: // CONSTRUCTORS TspGraphTmpl() : V3Graph{} {} - virtual ~TspGraphTmpl() override = default; + ~TspGraphTmpl() override = default; // METHODS void addVertex(const T_Key& key) { @@ -122,7 +122,7 @@ public: (new V3GraphEdge(this, tp, fp, cost))->user(userValue); } - inline static uint32_t getEdgeId(const V3GraphEdge* edgep) { + static uint32_t getEdgeId(const V3GraphEdge* edgep) { return static_cast(edgep->user()); } @@ -138,7 +138,7 @@ private: // We will keep sorted lists of edges as vectors using EdgeList = std::vector; - inline static bool edgeCmp(const V3GraphEdge* ap, const V3GraphEdge* bp) { + static bool edgeCmp(const V3GraphEdge* ap, const V3GraphEdge* bp) { // We pre-computed these when adding the edge to sort first by cost, then by identity return ap->user() > bp->user(); } @@ -150,7 +150,7 @@ private: } }; - inline static Vertex* castVertexp(V3GraphVertex* vxp) { return static_cast(vxp); } + static Vertex* castVertexp(V3GraphVertex* vxp) { return static_cast(vxp); } public: // From *this, populate *mstp with the minimum spanning tree. @@ -396,7 +396,7 @@ public: } } void dumpGraphFilePrefixed(const string& nameComment) const { - if (v3Global.opt.dumpTree()) { + if (::dump()) { const string filename = v3Global.debugFilename(nameComment) + ".txt"; const std::unique_ptr logp{V3File::new_ofstream(filename)}; if (logp->fail()) v3fatal("Can't write " << filename); @@ -406,7 +406,7 @@ public: void findEulerTour(std::vector* sortedOutp) { UASSERT(sortedOutp->empty(), "Output graph must start empty"); - if (debug() >= 6) dumpDotFilePrefixed("findEulerTour"); + if (::dumpGraph() >= 6) dumpDotFilePrefixed("findEulerTour"); std::unordered_set markedEdges; // Pick a start node Vertex* const start_vertexp = castVertexp(verticesBeginp()); @@ -464,12 +464,12 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) { // Create the minimum spanning tree Graph minGraph; graph.makeMinSpanningTree(&minGraph); - if (debug() >= 6) minGraph.dumpGraphFilePrefixed("minGraph"); + if (dumpGraph() >= 6) minGraph.dumpGraphFilePrefixed("minGraph"); const std::vector oddDegree = minGraph.getOddDegreeKeys(); Graph matching; graph.perfectMatching(oddDegree, &matching); - if (debug() >= 6) matching.dumpGraphFilePrefixed("matching"); + if (dumpGraph() >= 6) matching.dumpGraphFilePrefixed("matching"); // Adds edges to minGraph, the resulting graph will have even number of // edge counts at every vertex: @@ -542,8 +542,8 @@ public: : m_xpos{xpos} , m_ypos{ypos} , m_serial{++s_serialNext} {} - virtual ~TspTestState() override = default; - virtual int cost(const TspStateBase* otherp) const override { + ~TspTestState() override = default; + int cost(const TspStateBase* otherp) const override { return cost(dynamic_cast(otherp)); } static unsigned diff(unsigned a, unsigned b) { @@ -672,12 +672,12 @@ void V3TSP::selfTestString() { Graph minGraph; graph.makeMinSpanningTree(&minGraph); - if (debug() >= 6) minGraph.dumpGraphFilePrefixed("minGraph"); + if (dumpGraph() >= 6) minGraph.dumpGraphFilePrefixed("minGraph"); const std::vector oddDegree = minGraph.getOddDegreeKeys(); Graph matching; graph.perfectMatching(oddDegree, &matching); - if (debug() >= 6) matching.dumpGraphFilePrefixed("matching"); + if (dumpGraph() >= 6) matching.dumpGraphFilePrefixed("matching"); minGraph.combineGraph(matching); diff --git a/src/V3Table.cpp b/src/V3Table.cpp index e1f6cc2f0..8ace9f4f3 100644 --- a/src/V3Table.cpp +++ b/src/V3Table.cpp @@ -34,6 +34,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Table class functions @@ -59,12 +61,12 @@ class TableSimulateVisitor final : public SimulateVisitor { public: ///< Call other-this function on all new var references - virtual void varRefCb(AstVarRef* nodep) override; + void varRefCb(AstVarRef* nodep) override; // CONSTRUCTORS explicit TableSimulateVisitor(TableVisitor* cbthis) : m_cbthis{cbthis} {} - virtual ~TableSimulateVisitor() override = default; + ~TableSimulateVisitor() override = default; }; //###################################################################### @@ -169,7 +171,6 @@ private: std::vector m_outVarps; // Output variable list // METHODS - VL_DEBUG_FUNC; // Declare debug() public: void simulateVarRefCb(AstVarRef* nodep) { @@ -253,9 +254,9 @@ private: AstVar* const indexVarp = new AstVar{fl, VVarType::BLOCKTEMP, "__Vtableidx" + cvtToStr(m_modTables), VFlagBitPacked{}, static_cast(m_inWidthBits)}; - m_modp->addStmtp(indexVarp); + m_modp->addStmtsp(indexVarp); AstVarScope* const indexVscp = new AstVarScope{indexVarp->fileline(), m_scopep, indexVarp}; - m_scopep->addVarp(indexVscp); + m_scopep->addVarsp(indexVscp); // The 'output assigned' table builder TableBuilder outputAssignedTableBuilder{fl}; @@ -274,8 +275,8 @@ private: // Link it in. // Keep sensitivity list, but delete all else - nodep->bodysp()->unlinkFrBackWithNext()->deleteTree(); - nodep->addStmtp(stmtsp); + nodep->stmtsp()->unlinkFrBackWithNext()->deleteTree(); + nodep->addStmtsp(stmtsp); if (debug() >= 6) nodep->dumpTree(cout, " table_new: "); } @@ -298,8 +299,8 @@ private: uint32_t shift = 0; for (AstVarScope* invscp : m_inVarps) { // LSB is first variable, so extract it that way - const AstConst cnst(invscp->fileline(), AstConst::WidthedValue(), invscp->width(), - VL_MASK_I(invscp->width()) & (inValue >> shift)); + const AstConst cnst{invscp->fileline(), AstConst::WidthedValue{}, invscp->width(), + VL_MASK_I(invscp->width()) & (inValue >> shift)}; simvis.newValue(invscp, &cnst); shift += invscp->width(); // We are using 32 bit arithmetic, because there's no way the input table can be @@ -379,8 +380,8 @@ private: } // VISITORS - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNodeModule* nodep) override { VL_RESTORER(m_modp); VL_RESTORER(m_modTables); { @@ -389,20 +390,20 @@ private: iterateChildren(nodep); } } - virtual void visit(AstScope* nodep) override { + void visit(AstScope* nodep) override { UINFO(4, " SCOPE " << nodep << endl); m_scopep = nodep; iterateChildren(nodep); m_scopep = nullptr; } - virtual void visit(AstAlways* nodep) override { + void visit(AstAlways* nodep) override { UINFO(4, " ALWAYS " << nodep << endl); if (treeTest(nodep)) { // Well, then, I'll be a memory hog. replaceWithTable(nodep); } } - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { // It's nearly impossible to have a large enough assign to make this worthwhile // For now we won't bother. // Accelerated: no iterate @@ -411,7 +412,7 @@ private: public: // CONSTRUCTORS explicit TableVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~TableVisitor() override { // + ~TableVisitor() override { // V3Stats::addStat("Optimizations, Tables created", m_statTablesCre); } }; @@ -430,5 +431,5 @@ void TableSimulateVisitor::varRefCb(AstVarRef* nodep) { void V3Table::tableAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { TableVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("table", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("table", 0, dumpTree() >= 3); } diff --git a/src/V3Task.cpp b/src/V3Task.cpp index c736bb86b..1dd4c2cd1 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -38,6 +38,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Graph subclasses @@ -47,7 +49,7 @@ class TaskBaseVertex VL_NOT_FINAL : public V3GraphVertex { public: explicit TaskBaseVertex(V3Graph* graphp) : V3GraphVertex{graphp} {} - virtual ~TaskBaseVertex() override = default; + ~TaskBaseVertex() override = default; bool pure() const { return m_impurep == nullptr; } AstNode* impureNode() const { return m_impurep; } void impure(AstNode* nodep) { m_impurep = nodep; } @@ -64,10 +66,10 @@ public: TaskFTaskVertex(V3Graph* graphp, AstNodeFTask* nodep) : TaskBaseVertex{graphp} , m_nodep{nodep} {} - virtual ~TaskFTaskVertex() override = default; + ~TaskFTaskVertex() override = default; AstNodeFTask* nodep() const { return m_nodep; } - virtual string name() const override { return nodep()->name(); } - virtual string dotColor() const override { return pure() ? "black" : "red"; } + string name() const override { return nodep()->name(); } + string dotColor() const override { return pure() ? "black" : "red"; } AstCFunc* cFuncp() const { return m_cFuncp; } void cFuncp(AstCFunc* nodep) { m_cFuncp = nodep; } }; @@ -77,17 +79,17 @@ class TaskCodeVertex final : public TaskBaseVertex { public: explicit TaskCodeVertex(V3Graph* graphp) : TaskBaseVertex{graphp} {} - virtual ~TaskCodeVertex() override = default; - virtual string name() const override { return "*CODE*"; } - virtual string dotColor() const override { return "green"; } + ~TaskCodeVertex() override = default; + string name() const override { return "*CODE*"; } + string dotColor() const override { return "green"; } }; class TaskEdge final : public V3GraphEdge { public: TaskEdge(V3Graph* graphp, TaskBaseVertex* fromp, TaskBaseVertex* top) : V3GraphEdge{graphp, fromp, top, 1, false} {} - virtual ~TaskEdge() override = default; - virtual string dotLabel() const override { return "w" + cvtToStr(weight()); } + ~TaskEdge() override = default; + string dotLabel() const override { return "w" + cvtToStr(weight()); } }; //###################################################################### @@ -166,7 +168,7 @@ private: } // VISITORS - virtual void visit(AstScope* nodep) override { + void visit(AstScope* nodep) override { // Each FTask is unique per-scope, so AstNodeFTaskRefs do not need // pointers to what scope the FTask is to be invoked under. // However, to create variables, we need to track the scopes involved. @@ -186,12 +188,12 @@ private: } iterateChildren(nodep); } - virtual void visit(AstAssignW* nodep) override { + void visit(AstAssignW* nodep) override { m_assignwp = nodep; VL_DO_DANGLING(iterateChildren(nodep), nodep); // May delete nodep. m_assignwp = nullptr; } - virtual void visit(AstNodeFTaskRef* nodep) override { + void visit(AstNodeFTaskRef* nodep) override { // Includes handling AstMethodCall, AstNew if (m_assignwp) { // Wire assigns must become always statements to deal with insertion @@ -204,7 +206,7 @@ private: UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked task"); new TaskEdge(&m_callGraph, m_curVxp, getFTaskVertex(nodep->taskp())); } - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstNodeFTask* nodep) override { UINFO(9, " TASK " << nodep << endl); { VL_RESTORER(m_curVxp); @@ -221,7 +223,7 @@ private: iterateChildren(nodep); } } - virtual void visit(AstPragma* nodep) override { + void visit(AstPragma* nodep) override { if (nodep->pragType() == VPragmaType::NO_INLINE_TASK) { // Just mark for the next steps, and we're done with it. m_curVxp->noInline(true); @@ -230,17 +232,17 @@ private: iterateChildren(nodep); } } - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { iterateChildren(nodep); nodep->user4p(m_curVxp); // Remember what task it's under } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { iterateChildren(nodep); if (nodep->varp()->user4u().toGraphVertex() != m_curVxp) { if (m_curVxp->pure() && !nodep->varp()->isXTemp()) m_curVxp->impure(nodep); } } - virtual void visit(AstClass* nodep) override { + void visit(AstClass* nodep) override { // Move initial statements into the constructor m_initialps.clear(); m_ctorp = nullptr; @@ -250,7 +252,7 @@ private: } UASSERT_OBJ(m_ctorp, nodep, "class constructor missing"); // LinkDot always makes it for (AstInitialAutomatic* initialp : m_initialps) { - if (AstNode* const newp = initialp->bodysp()) { + if (AstNode* const newp = initialp->stmtsp()) { newp->unlinkFrBackWithNext(); if (!m_ctorp->stmtsp()) { m_ctorp->addStmtsp(newp); @@ -264,12 +266,12 @@ private: m_ctorp = nullptr; m_classp = nullptr; } - virtual void visit(AstInitialAutomatic* nodep) override { + void visit(AstInitialAutomatic* nodep) override { m_initialps.push_back(nodep); iterateChildren(nodep); } //-------------------- - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -281,9 +283,9 @@ public: iterate(nodep); // m_callGraph.removeRedundantEdgesSum(&TaskEdge::followAlwaysTrue); - m_callGraph.dumpDotFilePrefixed("task_call"); + if (dumpGraph()) m_callGraph.dumpDotFilePrefixed("task_call"); } - virtual ~TaskStateVisitor() override = default; + ~TaskStateVisitor() override = default; VL_UNCOPYABLE(TaskStateVisitor); }; @@ -364,14 +366,13 @@ private: DpiCFuncs m_dpiNames; // Map of all created DPI functions // METHODS - VL_DEBUG_FUNC; // Declare debug() AstVarScope* createFuncVar(AstCFunc* funcp, const string& name, AstVar* examplep) { AstVar* const newvarp = new AstVar(funcp->fileline(), VVarType::BLOCKTEMP, name, examplep); newvarp->funcLocal(true); funcp->addInitsp(newvarp); AstVarScope* const newvscp = new AstVarScope(funcp->fileline(), m_scopep, newvarp); - m_scopep->addVarp(newvscp); + m_scopep->addVarsp(newvscp); return newvscp; } AstVarScope* createInputVar(AstCFunc* funcp, const string& name, VBasicDTypeKwd kwd) { @@ -381,7 +382,7 @@ private: newvarp->direction(VDirection::INPUT); funcp->addArgsp(newvarp); AstVarScope* const newvscp = new AstVarScope(funcp->fileline(), m_scopep, newvarp); - m_scopep->addVarp(newvscp); + m_scopep->addVarsp(newvscp); return newvscp; } AstVarScope* createVarScope(AstVar* invarp, const string& name) { @@ -397,9 +398,9 @@ private: = new AstVar{invarp->fileline(), VVarType::BLOCKTEMP, name, invarp}; newvarp->funcLocal(false); newvarp->propagateAttrFrom(invarp); - m_modp->addStmtp(newvarp); + m_modp->addStmtsp(newvarp); AstVarScope* const newvscp = new AstVarScope{newvarp->fileline(), m_scopep, newvarp}; - m_scopep->addVarp(newvscp); + m_scopep->addVarsp(newvscp); return newvscp; } } @@ -496,7 +497,7 @@ private: // Put assignment in FRONT of all other statements if (AstNode* const afterp = beginp->nextp()) { afterp->unlinkFrBackWithNext(); - assp->addNext(afterp); + AstNode::addNext(assp, afterp); } beginp->addNext(assp); } @@ -766,7 +767,7 @@ private: funcp->protect(false); funcp->cname(nodep->cname()); // Add DPI Export to top, since it's a global function - m_topScopep->scopep()->addActivep(funcp); + m_topScopep->scopep()->addBlocksp(funcp); { // Create dispatch wrapper // Note this function may dispatch to myfunc on a different class. @@ -819,7 +820,7 @@ private: AstVarRef* const refp = new AstVarRef(portp->fileline(), outvscp, portp->isWritable() ? VAccess::WRITE : VAccess::READ); - argnodesp = argnodesp->addNextNull(refp); + argnodesp = argnodesp->addNext(refp); if (portp->isNonOutput()) { std::string frName @@ -847,7 +848,7 @@ private: outvscp->varp()->protect(false); AstVarRef* const refp = new AstVarRef( portp->fileline(), outvscp, portp->isWritable() ? VAccess::WRITE : VAccess::READ); - argnodesp = argnodesp->addNextNull(refp); + argnodesp = argnodesp->addNext(refp); } { // Call the user function @@ -855,9 +856,9 @@ private: // doesn't rip up the variables on us args += ");\n"; AstCStmt* const newp = new AstCStmt(nodep->fileline(), "(*__Vcb)("); - newp->addBodysp(argnodesp); + newp->addExprsp(argnodesp); VL_DANGLING(argnodesp); - newp->addBodysp(new AstText(nodep->fileline(), args, true)); + newp->addExprsp(new AstText(nodep->fileline(), args, true)); funcp->addStmtsp(newp); } @@ -899,7 +900,7 @@ private: funcp->protect(false); funcp->pure(nodep->pure()); // Add DPI Import to top, since it's a global function - m_topScopep->scopep()->addActivep(funcp); + m_topScopep->scopep()->addBlocksp(funcp); makePortList(nodep, funcp); return funcp; } @@ -1064,9 +1065,9 @@ private: FileLine* const fl = m_topScopep->fileline(); AstVar* const varp = new AstVar{fl, VVarType::VAR, "__Vdpi_export_trigger", VFlagBitPacked{}, 1}; - m_topScopep->scopep()->modp()->addStmtp(varp); + m_topScopep->scopep()->modp()->addStmtsp(varp); dpiExportTriggerp = new AstVarScope{fl, m_topScopep->scopep(), varp}; - m_topScopep->scopep()->addVarp(dpiExportTriggerp); + m_topScopep->scopep()->addVarsp(dpiExportTriggerp); v3Global.rootp()->dpiExportTriggerp(dpiExportTriggerp); } return dpiExportTriggerp; @@ -1134,7 +1135,7 @@ private: AstVarScope* rtnvscp = nullptr; if (rtnvarp) { rtnvscp = new AstVarScope(rtnvarp->fileline(), m_scopep, rtnvarp); - m_scopep->addVarp(rtnvscp); + m_scopep->addVarsp(rtnvscp); rtnvarp->user2p(rtnvscp); } @@ -1228,7 +1229,7 @@ private: } AstVarScope* const newvscp = new AstVarScope{portp->fileline(), m_scopep, portp}; - m_scopep->addVarp(newvscp); + m_scopep->addVarsp(newvscp); portp->user2p(newvscp); } } @@ -1314,9 +1315,9 @@ private: new AstVarRef{fl, dpiExportTriggerp, VAccess::READ}}}, nullptr}; for (AstVarScope* const varScopep : writtenps) { - alwaysp->addStmtp(new AstDpiExportUpdated{fl, varScopep}); + alwaysp->addStmtsp(new AstDpiExportUpdated{fl, varScopep}); } - m_scopep->addActivep(alwaysp); + m_scopep->addBlocksp(alwaysp); } } @@ -1366,7 +1367,7 @@ private: } // VISITORS - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { VL_RESTORER(m_modp); VL_RESTORER(m_modNCalls); { @@ -1376,13 +1377,13 @@ private: iterateChildren(nodep); } } - virtual void visit(AstScope* nodep) override { + void visit(AstScope* nodep) override { m_scopep = nodep; m_insStmtp = nullptr; iterateChildren(nodep); m_scopep = nullptr; } - virtual void visit(AstNodeFTaskRef* nodep) override { + void visit(AstNodeFTaskRef* nodep) override { // Includes handling AstMethodCall, AstNew UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked?"); iterateIntoFTask(nodep->taskp()); // First, do hierarchical funcs @@ -1436,7 +1437,7 @@ private: // Visit nodes that normal iteration won't find if (visitp) iterateAndNextNull(visitp); } - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstNodeFTask* nodep) override { UINFO(4, " visitFTask " << nodep << endl); VL_RESTORER(m_insMode); VL_RESTORER(m_insStmtp); @@ -1504,7 +1505,7 @@ private: VL_DO_DANGLING(pushDeletep(nodep), nodep); } } - virtual void visit(AstWhile* nodep) override { + void visit(AstWhile* nodep) override { // Special, as statements need to be put in different places // Preconditions insert first just before themselves (the normal // rule for other statement types) @@ -1516,16 +1517,16 @@ private: iterateAndNextNull(nodep->condp()); // Body insert just before themselves m_insStmtp = nullptr; // First thing should be new statement - iterateAndNextNull(nodep->bodysp()); + iterateAndNextNull(nodep->stmtsp()); iterateAndNextNull(nodep->incsp()); // Done the loop m_insStmtp = nullptr; // Next thing should be new statement } - virtual void visit(AstNodeFor* nodep) override { // LCOV_EXCL_LINE + void visit(AstNodeFor* nodep) override { // LCOV_EXCL_LINE nodep->v3fatalSrc( "For statements should have been converted to while statements in V3Begin.cpp"); } - virtual void visit(AstNodeStmt* nodep) override { + void visit(AstNodeStmt* nodep) override { if (!nodep->isStatement()) { iterateChildren(nodep); return; @@ -1536,7 +1537,7 @@ private: m_insStmtp = nullptr; // Next thing should be new statement } //-------------------- - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -1544,7 +1545,7 @@ public: : m_statep{statep} { iterate(nodep); } - virtual ~TaskVisitor() override = default; + ~TaskVisitor() override = default; }; //###################################################################### @@ -1814,5 +1815,5 @@ void V3Task::taskAll(AstNetlist* nodep) { TaskStateVisitor visitors{nodep}; const TaskVisitor visitor{nodep, &visitors}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("task", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("task", 0, dumpTree() >= 3); } diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index 9a1fe1e3c..b19b1c249 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -50,6 +50,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Graph vertexes @@ -73,20 +75,20 @@ public: m_activityCode = code; m_slow = false; } - virtual ~TraceActivityVertex() override = default; + ~TraceActivityVertex() override = default; // ACCESSORS AstNode* insertp() const { if (!m_insertp) v3fatalSrc("Null insertp; probably called on a special always/slow."); return m_insertp; } - virtual string name() const override { + string name() const override { if (activityAlways()) { return "*ALWAYS*"; } else { return std::string{slow() ? "*SLOW* " : ""} + insertp()->name(); } } - virtual string dotColor() const override { return slow() ? "yellowGreen" : "green"; } + string dotColor() const override { return slow() ? "yellowGreen" : "green"; } int32_t activityCode() const { return m_activityCode; } bool activityAlways() const { return activityCode() == ACTIVITY_ALWAYS; } bool activitySlow() const { return activityCode() == ACTIVITY_SLOW; } @@ -104,12 +106,12 @@ public: TraceCFuncVertex(V3Graph* graphp, AstCFunc* nodep) : V3GraphVertex{graphp} , m_nodep{nodep} {} - virtual ~TraceCFuncVertex() override = default; + ~TraceCFuncVertex() override = default; // ACCESSORS AstCFunc* nodep() const { return m_nodep; } - virtual string name() const override { return nodep()->name(); } - virtual string dotColor() const override { return "yellow"; } - virtual FileLine* fileline() const override { return nodep()->fileline(); } + string name() const override { return nodep()->name(); } + string dotColor() const override { return "yellow"; } + FileLine* fileline() const override { return nodep()->fileline(); } }; class TraceTraceVertex final : public V3GraphVertex { @@ -121,12 +123,12 @@ public: TraceTraceVertex(V3Graph* graphp, AstTraceDecl* nodep) : V3GraphVertex{graphp} , m_nodep{nodep} {} - virtual ~TraceTraceVertex() override = default; + ~TraceTraceVertex() override = default; // ACCESSORS AstTraceDecl* nodep() const { return m_nodep; } - virtual string name() const override { return nodep()->name(); } - virtual string dotColor() const override { return "red"; } - virtual FileLine* fileline() const override { return nodep()->fileline(); } + string name() const override { return nodep()->name(); } + string dotColor() const override { return "red"; } + FileLine* fileline() const override { return nodep()->fileline(); } TraceTraceVertex* duplicatep() const { return m_duplicatep; } void duplicatep(TraceTraceVertex* dupp) { UASSERT_OBJ(!duplicatep(), nodep(), "Assigning duplicatep() to already duplicated node"); @@ -141,12 +143,12 @@ public: TraceVarVertex(V3Graph* graphp, AstVarScope* nodep) : V3GraphVertex{graphp} , m_nodep{nodep} {} - virtual ~TraceVarVertex() override = default; + ~TraceVarVertex() override = default; // ACCESSORS AstVarScope* nodep() const { return m_nodep; } - virtual string name() const override { return nodep()->name(); } - virtual string dotColor() const override { return "skyblue"; } - virtual FileLine* fileline() const override { return nodep()->fileline(); } + string name() const override { return nodep()->name(); } + string dotColor() const override { return "skyblue"; } + FileLine* fileline() const override { return nodep()->fileline(); } }; //###################################################################### @@ -194,7 +196,6 @@ private: using TraceVec = std::multimap; // METHODS - VL_DEBUG_FUNC; // Declare debug() void detectDuplicates() { UINFO(9, "Finding duplicates\n"); @@ -454,9 +455,9 @@ private: v3Global.rootp()->typeTablep()->addTypesp(newArrDtp); AstVar* const newvarp = new AstVar(flp, VVarType::MODULETEMP, "__Vm_traceActivity", newArrDtp); - m_topModp->addStmtp(newvarp); + m_topModp->addStmtsp(newvarp); AstVarScope* const newvscp = new AstVarScope(flp, m_topScopep, newvarp); - m_topScopep->addVarp(newvscp); + m_topScopep->addVarsp(newvscp); m_activityVscp = newvscp; // Insert activity setters @@ -493,7 +494,7 @@ private: funcp->slow(full); funcp->isStatic(isTopFunc); // Add it to top scope - m_topScopep->addActivep(funcp); + m_topScopep->addBlocksp(funcp); const auto addInitStr = [funcp, flp](const string& str) -> void { funcp->addInitsp(new AstCStmt(flp, str)); }; @@ -676,7 +677,7 @@ private: // Add TraceInc node AstTraceInc* const incp = new AstTraceInc(declp->fileline(), declp, /* full: */ false, baseCode); - ifp->addIfsp(incp); + ifp->addThensp(incp); subStmts += incp->nodeCount(); // Track partitioning @@ -698,7 +699,7 @@ private: cleanupFuncp->slow(false); cleanupFuncp->isStatic(true); cleanupFuncp->isLoose(true); - m_topScopep->addActivep(cleanupFuncp); + m_topScopep->addBlocksp(cleanupFuncp); cleanupFuncp->addInitsp(new AstCStmt(fl, voidSelfAssign(m_topModp))); cleanupFuncp->addInitsp(new AstCStmt(fl, symClassAssign())); @@ -724,11 +725,11 @@ private: detectDuplicates(); // Simplify & optimize the graph - if (debug() >= 6) m_graph.dumpDotFilePrefixed("trace_pre"); + if (dumpGraph() >= 6) m_graph.dumpDotFilePrefixed("trace_pre"); graphSimplify(true); - if (debug() >= 6) m_graph.dumpDotFilePrefixed("trace_simplified"); + if (dumpGraph() >= 6) m_graph.dumpDotFilePrefixed("trace_simplified"); graphOptimize(); - if (debug() >= 6) m_graph.dumpDotFilePrefixed("trace_optimized"); + if (dumpGraph() >= 6) m_graph.dumpDotFilePrefixed("trace_optimized"); // Create the fine grained activity flags createActivityFlags(); @@ -755,7 +756,7 @@ private: m_regFuncp->slow(true); m_regFuncp->isStatic(false); m_regFuncp->isLoose(true); - m_topScopep->addActivep(m_regFuncp); + m_topScopep->addBlocksp(m_regFuncp); // Create the full dump functions, also allocates signal numbers createFullTraceFunction(traces, nFullCodes, m_parallelism); @@ -796,7 +797,7 @@ private: } // VISITORS - virtual void visit(AstNetlist* nodep) override { + void visit(AstNetlist* nodep) override { m_code = 1; // Multiple TopScopes will require fixing how code#s // are assigned as duplicate varscopes must result in the same tracing code#. @@ -811,11 +812,11 @@ private: // Create the trace functions and insert them into the tree createTraceFunctions(); } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { if (nodep->isTop()) m_topModp = nodep; iterateChildren(nodep); } - virtual void visit(AstCCall* nodep) override { + void visit(AstCCall* nodep) override { UINFO(8, " CCALL " << nodep << endl); if (!m_finding && !nodep->user2()) { // See if there are other calls in same statement list; @@ -834,7 +835,7 @@ private: } iterateChildren(nodep); } - virtual void visit(AstCFunc* nodep) override { + void visit(AstCFunc* nodep) override { UINFO(8, " CFUNC " << nodep << endl); V3GraphVertex* const funcVtxp = getCFuncVertexp(nodep); if (!m_finding) { // If public, we need a unique activity code to allow for sets @@ -851,7 +852,7 @@ private: iterateChildren(nodep); } } - virtual void visit(AstTraceDecl* nodep) override { + void visit(AstTraceDecl* nodep) override { UINFO(8, " TRACE " << nodep << endl); if (!m_finding) { V3GraphVertex* const vertexp = new TraceTraceVertex(&m_graph, nodep); @@ -863,7 +864,7 @@ private: m_tracep = nullptr; } } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { if (m_tracep) { UASSERT_OBJ(nodep->varScopep(), nodep, "No var scope?"); UASSERT_OBJ(nodep->access().isReadOnly(), nodep, "Lvalue in trace? Should be const."); @@ -888,7 +889,7 @@ private: } } //-------------------- - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -896,7 +897,7 @@ public: : m_alwaysVtxp{new TraceActivityVertex{&m_graph, TraceActivityVertex::ACTIVITY_ALWAYS}} { iterate(nodep); } - virtual ~TraceVisitor() override { + ~TraceVisitor() override { V3Stats::addStat("Tracing, Unique traced signals", m_statUniqSigs); V3Stats::addStat("Tracing, Unique trace codes", m_statUniqCodes); } @@ -908,5 +909,5 @@ public: void V3Trace::traceAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { TraceVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("trace", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("trace", 0, dumpTree() >= 3); } diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index 6fc9a8726..41db6e5ab 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -37,6 +37,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Utility class to emit path adjustments @@ -133,7 +135,6 @@ private: VDouble0 m_statIgnSigs; // Statistic tracking // METHODS - VL_DEBUG_FUNC; // Declare debug() const char* vscIgnoreTrace(const AstVarScope* nodep) { // Return true if this shouldn't be traced @@ -162,7 +163,7 @@ private: funcp->isStatic(false); funcp->isLoose(true); funcp->slow(true); - topScopep->addActivep(funcp); + topScopep->addBlocksp(funcp); return funcp; } @@ -241,7 +242,7 @@ private: } // VISITORS - virtual void visit(AstScope* nodep) override { + void visit(AstScope* nodep) override { UASSERT_OBJ(!m_currScopep, nodep, "Should not nest"); UASSERT_OBJ(m_subFuncps.empty(), nodep, "Should not nest"); UASSERT_OBJ(m_signals.empty(), nodep, "Should not nest"); @@ -280,11 +281,7 @@ private: addIgnore(ignoreReasonp); } else { ++m_statSigs; - if (AstNode* const valuep = m_traVscp->valuep()) { - m_traValuep = valuep->cloneTree(false); - } else { - m_traValuep = new AstVarRef{m_traVscp->fileline(), m_traVscp, VAccess::READ}; - } + m_traValuep = new AstVarRef{m_traVscp->fileline(), m_traVscp, VAccess::READ}; // Recurse into data type of the signal. The visit methods will add AstTraceDecls. iterate(m_traVscp->varp()->dtypep()->skipRefToEnump()); // Cleanup @@ -307,8 +304,8 @@ private: scopeName = scopeName.substr(0, lastDot + 1); const size_t scopeLen = scopeName.length(); - UASSERT_OBJ(cellp->intfRefp(), cellp, "Interface without tracing reference"); - for (AstIntfRef *irp = cellp->intfRefp(), *nextIrp; irp; irp = nextIrp) { + UASSERT_OBJ(cellp->intfRefsp(), cellp, "Interface without tracing reference"); + for (AstIntfRef *irp = cellp->intfRefsp(), *nextIrp; irp; irp = nextIrp) { nextIrp = VN_AS(irp->nextp(), IntfRef); const string irpName = irp->prettyName(); @@ -334,7 +331,7 @@ private: m_scopeSubFuncps.emplace(scopeName, std::move(m_subFuncps)); } } - virtual void visit(AstVarScope* nodep) override { + void visit(AstVarScope* nodep) override { UASSERT_OBJ(m_currScopep, nodep, "AstVarScope not under AstScope"); // Prefilter - things that get added to m_vscps will either get traced or get a comment as @@ -349,13 +346,13 @@ private: } // VISITORS - Data types when tracing - virtual void visit(AstConstDType* nodep) override { + void visit(AstConstDType* nodep) override { if (m_traVscp) iterate(nodep->subDTypep()->skipRefToEnump()); } - virtual void visit(AstRefDType* nodep) override { + void visit(AstRefDType* nodep) override { if (m_traVscp) iterate(nodep->subDTypep()->skipRefToEnump()); } - virtual void visit(AstUnpackArrayDType* nodep) override { + void visit(AstUnpackArrayDType* nodep) override { // Note more specific dtypes above if (m_traVscp) { if (static_cast(nodep->arrayUnpackedElements()) > v3Global.opt.traceMaxArray()) { @@ -390,13 +387,13 @@ private: } } } - virtual void visit(AstPackArrayDType* nodep) override { + void visit(AstPackArrayDType* nodep) override { if (m_traVscp) { if (!v3Global.opt.traceStructs()) { // Everything downstream is packed, so deal with as one trace unit. // This may not be the nicest for user presentation, but is // a much faster way to trace - addTraceDecl(VNumRange(), nodep->width()); + addTraceDecl(VNumRange{}, nodep->width()); } else { FileLine* const flp = nodep->fileline(); AstNodeDType* const subtypep = nodep->subDTypep()->skipRefToEnump(); @@ -416,13 +413,13 @@ private: } } } - virtual void visit(AstNodeUOrStructDType* nodep) override { + void visit(AstNodeUOrStructDType* nodep) override { if (m_traVscp) { if (nodep->packed() && !v3Global.opt.traceStructs()) { // Everything downstream is packed, so deal with as one trace unit // This may not be the nicest for user presentation, but is // a much faster way to trace - addTraceDecl(VNumRange(), nodep->width()); + addTraceDecl(VNumRange{}, nodep->width()); } else if (!nodep->packed()) { addIgnore("Unsupported: Unpacked struct/union"); } else { @@ -453,24 +450,24 @@ private: } } } - virtual void visit(AstBasicDType* nodep) override { + void visit(AstBasicDType* nodep) override { if (m_traVscp) { if (nodep->isString()) { addIgnore("Unsupported: strings"); } else { - addTraceDecl(VNumRange(), 0); + addTraceDecl(VNumRange{}, 0); } } } - virtual void visit(AstEnumDType* nodep) override { iterate(nodep->skipRefp()); } - virtual void visit(AstNodeDType*) override { + void visit(AstEnumDType* nodep) override { iterate(nodep->skipRefp()); } + void visit(AstNodeDType*) override { // Note more specific dtypes above if (!m_traVscp) return; addIgnore("Unsupported: data type"); } //-------------------- - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -517,7 +514,7 @@ public: AstCFunc* const topFuncp = m_topFuncps.front(); topFuncp->name("trace_init_top"); } - virtual ~TraceDeclVisitor() override { + ~TraceDeclVisitor() override { V3Stats::addStat("Tracing, Traced signals", m_statSigs); V3Stats::addStat("Tracing, Ignored signals", m_statIgnSigs); } @@ -529,5 +526,5 @@ public: void V3TraceDecl::traceDeclAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { TraceDeclVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("tracedecl", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("tracedecl", 0, dumpTree() >= 3); } diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index b5e983978..55dddaacc 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -55,6 +55,64 @@ // duplicating vars and logic that is common between each instance of a // module. // +// +// Another thing done in this phase is signal strength handling. +// Currently they are only supported in assignments and gates parsed as assignments (see verilog.y) +// when any of the cases occurs: +// - it is possible to statically resolve all drivers, +// - all assignments that passed the static resolution have symmetric strengths (the same strength +// is related to both 0 and 1 values). +// +// It is possible to statically resolve all drivers when the strongest assignment has RHS marked as +// non-tristate. If the RHS is equal to z, that assignment has to be skipped. Since the value may +// be not known at verilation time, cases with tristates on RHS can't be handled statically. +// +// Static resolution is split into 2 parts. +// First part can be done before tristate propagation. It is about removing assignments that are +// weaker or equally strong as the strongest assignment with constant on RHS that has all bits +// the same (equal to 0 or 1). It is done in the following way: +// - The assignment of value 0 (size may be greater than 1), that has greatest strength (the +// one corresponding to 0) of all other assignments of 0, has to be found. +// - The same is done for value '1 and strength corresponding to value 1. +// - The greater of these two strengths is chosen. If they are equal the one that corresponds +// to 1 is taken as the greatest. +// - All assignments, that have strengths weaker or equal to the one that was found before, are +// removed. They are the assignments with constants on the RHS and also all assignments that have +// both strengths non-greater that the one was found, because they are weaker no matter what is on +// RHS. +// +// Second part of static resolution is done after tristate propagation. +// At that moment it is known that some expressions can't be equal to z. The exact value is +// unknown (except the ones with constants that were handled before), so weaker of both strengths +// has to be taken into account. All weaker assignments can be safely removed. It is done in +// similar way to the first part: +// - The assignment with non-tristate RHS with the greatest weaker strength has to be found. +// - Then all not stronger assignments can be removed. +// +// All assignments that are stronger than the strongest with non-tristate RHS are then tried to be +// handled dynamically. Currently it is supported only on assignments with symmetric strengths. +// In this case, the exact value of the RHS doesn't matter. It only matters if it equals z or not. +// Such assignments are handled by changing the values to z of these bits that are overwritten by +// stronger assignments. Then all assignments can be aggregated as they would have equal strengths +// (by | on them and their __en expressions). To change the value to z, the RHS should be & with +// negation of __en expression of stronger assignments. Changing RHS's __en expression is not +// needed, because it will be then aggregated with __en expression of stronger assignments using |, +// so & with the negation can be safely skipped. +// So the values of overwritten bits are actually changed to 0, which doesn't affect stronger +// assignments, because | operation was used. +// +// Dynamic handling is implemented in the following way: +// - group the assignments by their strengths, +// - handle assignments of the same strength by aggregating values with | +// - assign results to var__strength and var__strength__en variables +// - aggregate the results: +// orp = orp | (var__strength & ~enp) +// enp = enp | var__strength__en, +// where orp is aggregated value and enp is aggregated __en value. +// +// There is a possible problem with equally strong assignments, because multiple assignments with +// the same strength, but different values should result in x value, but these values are +// unsupported. //************************************************************************* #include "config_build.h" @@ -71,12 +129,13 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### class TristateBaseVisitor VL_NOT_FINAL : public VNVisitor { public: // METHODS - VL_DEBUG_FUNC; // Declare debug() }; //###################################################################### @@ -91,17 +150,17 @@ public: TristateVertex(V3Graph* graphp, AstNode* nodep) : V3GraphVertex{graphp} , m_nodep{nodep} {} - virtual ~TristateVertex() override = default; + ~TristateVertex() override = default; // ACCESSORS AstNode* nodep() const { return m_nodep; } const AstVar* varp() const { return VN_CAST(nodep(), Var); } - virtual string name() const override { + string name() const override { return ((isTristate() ? "tri\\n" : feedsTri() ? "feed\\n" : "-\\n") + (nodep()->prettyTypeName() + " " + cvtToHex(nodep()))); } - virtual string dotColor() const override { + string dotColor() const override { return (varp() ? (isTristate() ? "darkblue" : feedsTri() ? "blue" : "lightblue") @@ -109,7 +168,7 @@ public: : feedsTri() ? "green" : "lightgreen")); } - virtual FileLine* fileline() const override { return nodep()->fileline(); } + FileLine* fileline() const override { return nodep()->fileline(); } void isTristate(bool flag) { m_isTristate = flag; } bool isTristate() const { return m_isTristate; } void feedsTri(bool flag) { m_feedsTri = flag; } @@ -141,7 +200,6 @@ public: private: // METHODS - VL_DEBUG_FUNC; // Declare debug() TristateVertex* makeVertex(AstNode* nodep) { TristateVertex* vertexp = reinterpret_cast(nodep->user5p()); @@ -229,7 +287,6 @@ public: AstNode::user5ClearTree(); // Wipe all node user5p's that point to vertexes } void graphWalk(AstNodeModule* nodep) { - // if (debug() >= 9) m_graph.dumpDotFilePrefixed("tri_pre__" + nodep->name()); UINFO(9, " Walking " << nodep << endl); for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { graphWalkRecurseFwd(static_cast(itp), 0); @@ -237,11 +294,23 @@ public: for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { graphWalkRecurseBack(static_cast(itp), 0); } - if (debug() >= 9) m_graph.dumpDotFilePrefixed("tri_pos__" + nodep->name()); + if (dumpGraph() >= 9) m_graph.dumpDotFilePrefixed("tri_pos__" + nodep->name()); } void associate(AstNode* fromp, AstNode* top) { new V3GraphEdge(&m_graph, makeVertex(fromp), makeVertex(top), 1); } + void deleteVerticesFromSubtreeRecurse(AstNode* nodep) { + if (!nodep) return; + // Skip vars, because they may be connected to more than one varref + if (!VN_IS(nodep, Var)) { + TristateVertex* const vertexp = reinterpret_cast(nodep->user5p()); + if (vertexp) vertexp->unlinkDelete(&m_graph); + } + deleteVerticesFromSubtreeRecurse(nodep->op1p()); + deleteVerticesFromSubtreeRecurse(nodep->op2p()); + deleteVerticesFromSubtreeRecurse(nodep->op3p()); + deleteVerticesFromSubtreeRecurse(nodep->op4p()); + } void setTristate(AstNode* nodep) { makeVertex(nodep)->isTristate(true); } bool isTristate(AstNode* nodep) { const TristateVertex* const vertexp = reinterpret_cast(nodep->user5p()); @@ -285,7 +354,7 @@ class TristatePinVisitor final : public TristateBaseVisitor { TristateGraph& m_tgraph; const bool m_lvalue; // Flip to be an LVALUE // VISITORS - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { UASSERT_OBJ(!nodep->access().isRW(), nodep, "Tristate unexpected on R/W access flip"); if (m_lvalue && !nodep->access().isWriteOrRW()) { UINFO(9, " Flip-to-LValue " << nodep << endl); @@ -298,17 +367,17 @@ class TristatePinVisitor final : public TristateBaseVisitor { m_tgraph.setTristate(nodep->varp()); } } - virtual void visit(AstArraySel* nodep) override { + void visit(AstArraySel* nodep) override { // Doesn't work because we'd set lvalue on the array index's var UASSERT_OBJ(!m_lvalue, nodep, "ArraySel conversion to output, under tristate node"); iterateChildren(nodep); } - virtual void visit(AstSliceSel* nodep) override { + void visit(AstSliceSel* nodep) override { // Doesn't work because we'd set lvalue on the array index's var UASSERT_OBJ(!m_lvalue, nodep, "SliceSel conversion to output, under tristate node"); iterateChildren(nodep); } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -317,7 +386,7 @@ public: , m_lvalue{lvalue} { iterate(nodep); } - virtual ~TristatePinVisitor() override = default; + ~TristatePinVisitor() override = default; }; //###################################################################### @@ -338,8 +407,17 @@ class TristateVisitor final : public TristateBaseVisitor { const VNUser5InUse m_inuser5; // TYPES - using RefVec = std::vector; - using VarMap = std::unordered_map; + struct RefStrength { + AstVarRef* m_varrefp; + VStrength m_strength; + RefStrength(AstVarRef* varrefp, VStrength strength) + : m_varrefp{varrefp} + , m_strength{strength} {} + }; + using RefStrengthVec = std::vector; + using VarMap = std::unordered_map; + using Assigns = std::vector; + using VarToAssignsMap = std::map; enum : uint8_t { U2_GRAPHING = 1, // bit[0] if did m_graphing visit U2_NONGRAPH = 2, // bit[1] if did !m_graphing visit @@ -352,8 +430,11 @@ class TristateVisitor final : public TristateBaseVisitor { AstNodeModule* m_modp = nullptr; // Current module AstCell* m_cellp = nullptr; // current cell VarMap m_lhsmap; // Tristate left-hand-side driver map + VarToAssignsMap m_assigns; // Assigns in current module int m_unique = 0; bool m_alhs = false; // On LHS of assignment + VStrength m_currentStrength = VStrength::STRONG; // Current strength of assignment, + // Used only on LHS of assignment const AstNode* m_logicp = nullptr; // Current logic being built TristateGraph m_tgraph; // Logic graph @@ -372,7 +453,7 @@ class TristateVisitor final : public TristateBaseVisitor { "Unsupported: Creating tristate signal not underneath a module: " << nodep->prettyNameQ()); } else { - m_modp->addStmtp(newp); + m_modp->addStmtsp(newp); } } void associateLogic(AstNode* fromp, AstNode* top) { @@ -436,11 +517,11 @@ class TristateVisitor final : public TristateBaseVisitor { const auto it = m_lhsmap.find(key); UINFO(9, " mapInsertLhsVarRef " << nodep << endl); if (it == m_lhsmap.end()) { // Not found - RefVec* const refsp = new RefVec; - refsp->push_back(nodep); + RefStrengthVec* const refsp = new RefStrengthVec; + refsp->push_back(RefStrength{nodep, m_currentStrength}); m_lhsmap.emplace(key, refsp); } else { - it->second->push_back(nodep); + it->second->push_back(RefStrength{nodep, m_currentStrength}); } } @@ -504,7 +585,7 @@ class TristateVisitor final : public TristateBaseVisitor { AstNode* const newp = new AstAssignW(varp->fileline(), varrefp, constp); UINFO(9, " newoev " << newp << endl); varrefp->user1p(newAllZerosOrOnes(varp, false)); - nodep->addStmtp(newp); + nodep->addStmtsp(newp); mapInsertLhsVarRef(varrefp); // insertTristates will convert // // to a varref to the __out# variable } @@ -518,7 +599,7 @@ class TristateVisitor final : public TristateBaseVisitor { nextit = it; ++nextit; AstVar* const invarp = it->first; - const RefVec* const refsp = it->second; + RefStrengthVec* refsp = it->second; // Figure out if this var needs tristate expanded. if (m_tgraph.isTristate(invarp)) { insertTristatesSignal(nodep, invarp, refsp); @@ -531,8 +612,64 @@ class TristateVisitor final : public TristateBaseVisitor { } } - void insertTristatesSignal(AstNodeModule* nodep, AstVar* const invarp, - const RefVec* const refsp) { + void aggregateTriSameStrength(AstNodeModule* nodep, AstVar* const varp, AstVar* const envarp, + RefStrengthVec::iterator beginStrength, + RefStrengthVec::iterator endStrength) { + // For each driver seperate variables (normal and __en) are created and initialized with + // values. In case of normal variable, the original expression is reused. Their values are + // aggregated using | to form one expression, which are assigned to varp end envarp. + AstNode* orp = nullptr; + AstNode* enp = nullptr; + + for (auto it = beginStrength; it != endStrength; it++) { + AstVarRef* refp = it->m_varrefp; + const int w = varp->width(); + + // create the new lhs driver for this var + AstVar* const newLhsp = new AstVar{varp->fileline(), VVarType::MODULETEMP, + varp->name() + "__out" + cvtToStr(m_unique), + VFlagBitPacked{}, w}; // 2-state ok; sep enable + UINFO(9, " newout " << newLhsp << endl); + nodep->addStmtsp(newLhsp); + refp->varp(newLhsp); // assign the new var to the varref + refp->name(newLhsp->name()); + + // create a new var for this drivers enable signal + AstVar* const newEnLhsp = new AstVar{varp->fileline(), VVarType::MODULETEMP, + varp->name() + "__en" + cvtToStr(m_unique++), + VFlagBitPacked{}, w}; // 2-state ok + UINFO(9, " newenlhsp " << newEnLhsp << endl); + nodep->addStmtsp(newEnLhsp); + + AstNode* const enLhspAssignp = new AstAssignW{ + refp->fileline(), new AstVarRef{refp->fileline(), newEnLhsp, VAccess::WRITE}, + getEnp(refp)}; + UINFO(9, " newenlhspAssignp " << enLhspAssignp << endl); + nodep->addStmtsp(enLhspAssignp); + + // now append this driver to the driver logic. + AstNode* const ref1p = new AstVarRef{refp->fileline(), newLhsp, VAccess::READ}; + AstNode* const ref2p = new AstVarRef{refp->fileline(), newEnLhsp, VAccess::READ}; + AstNode* const andp = new AstAnd{refp->fileline(), ref1p, ref2p}; + + // or this to the others + orp = (!orp) ? andp : new AstOr{refp->fileline(), orp, andp}; + + AstNode* const ref3p = new AstVarRef{refp->fileline(), newEnLhsp, VAccess::READ}; + enp = (!enp) ? ref3p : new AstOr{ref3p->fileline(), enp, ref3p}; + } + AstNode* const assp = new AstAssignW{ + varp->fileline(), new AstVarRef{varp->fileline(), varp, VAccess::WRITE}, orp}; + UINFO(9, " newassp " << assp << endl); + nodep->addStmtsp(assp); + + AstNode* const enAssp = new AstAssignW{ + envarp->fileline(), new AstVarRef{envarp->fileline(), envarp, VAccess::WRITE}, enp}; + UINFO(9, " newenassp " << enAssp << endl); + nodep->addStmtsp(enAssp); + } + + void insertTristatesSignal(AstNodeModule* nodep, AstVar* const invarp, RefStrengthVec* refsp) { UINFO(8, " TRISTATE EXPANDING:" << invarp << endl); ++m_statTriSigs; m_tgraph.didProcess(invarp); @@ -566,78 +703,245 @@ class TristateVisitor final : public TristateBaseVisitor { AstNode* orp = nullptr; AstNode* enp = nullptr; - AstNode* undrivenp = nullptr; + const int w = lhsp->width(); - // loop through the lhs drivers to build the driver resolution logic - for (auto refp : *refsp) { - const int w = lhsp->width(); + std::sort(refsp->begin(), refsp->end(), + [](RefStrength a, RefStrength b) { return a.m_strength > b.m_strength; }); - // create the new lhs driver for this var - AstVar* const newlhsp = new AstVar(lhsp->fileline(), VVarType::MODULETEMP, - lhsp->name() + "__out" + cvtToStr(m_unique), - VFlagBitPacked(), w); // 2-state ok; sep enable - UINFO(9, " newout " << newlhsp << endl); - nodep->addStmtp(newlhsp); - refp->varp(newlhsp); // assign the new var to the varref - refp->name(newlhsp->name()); + auto beginStrength = refsp->begin(); + while (beginStrength != refsp->end()) { + auto endStrength = beginStrength + 1; + while (endStrength != refsp->end() + && endStrength->m_strength == beginStrength->m_strength) + endStrength++; - // create a new var for this drivers enable signal - AstVar* const newenp = new AstVar(lhsp->fileline(), VVarType::MODULETEMP, - lhsp->name() + "__en" + cvtToStr(m_unique++), - VFlagBitPacked(), w); // 2-state ok - UINFO(9, " newenp " << newenp << endl); - nodep->addStmtp(newenp); + FileLine* const fl = beginStrength->m_varrefp->fileline(); + const string strengthVarName = lhsp->name() + "__" + beginStrength->m_strength.ascii(); - AstNode* const enassp = new AstAssignW( - refp->fileline(), new AstVarRef(refp->fileline(), newenp, VAccess::WRITE), - getEnp(refp)); - UINFO(9, " newass " << enassp << endl); - nodep->addStmtp(enassp); + // var__strength variable + AstVar* varStrengthp = new AstVar{fl, VVarType::MODULETEMP, strengthVarName, + VFlagBitPacked{}, w}; // 2-state ok; sep enable; + UINFO(9, " newstrength " << varStrengthp << endl); + nodep->addStmtsp(varStrengthp); - // now append this driver to the driver logic. - AstNode* const ref1p = new AstVarRef(refp->fileline(), newlhsp, VAccess::READ); - AstNode* const ref2p = new AstVarRef(refp->fileline(), newenp, VAccess::READ); - AstNode* const andp = new AstAnd(refp->fileline(), ref1p, ref2p); + // var__strength__en variable + AstVar* enVarStrengthp = new AstVar{fl, VVarType::MODULETEMP, strengthVarName + "__en", + VFlagBitPacked{}, w}; // 2-state ok; + UINFO(9, " newenstrength " << enVarStrengthp << endl); + nodep->addStmtsp(enVarStrengthp); - // or this to the others - orp = (!orp) ? andp : new AstOr(refp->fileline(), orp, andp); + aggregateTriSameStrength(nodep, varStrengthp, enVarStrengthp, beginStrength, + endStrength); - if (envarp) { - AstNode* const ref3p = new AstVarRef(refp->fileline(), newenp, VAccess::READ); - enp = (!enp) ? ref3p : new AstOr(ref3p->fileline(), enp, ref3p); + AstNode* exprCurrentStrengthp; + if (enp) { + // If weaker driver should be overwritten by a stronger, replace its value with z + exprCurrentStrengthp + = new AstAnd{fl, new AstVarRef{fl, varStrengthp, VAccess::READ}, + new AstNot{fl, enp->cloneTree(false)}}; + } else { + exprCurrentStrengthp = new AstVarRef{fl, varStrengthp, VAccess::READ}; } - AstNode* const tmp = new AstNot( - newenp->fileline(), new AstVarRef(newenp->fileline(), newenp, VAccess::READ)); - undrivenp = ((!undrivenp) ? tmp : new AstAnd(refp->fileline(), tmp, undrivenp)); - } - if (!undrivenp) { // No drivers on the bus - undrivenp = newAllZerosOrOnes(invarp, true); + orp = (!orp) ? exprCurrentStrengthp : new AstOr{fl, orp, exprCurrentStrengthp}; + + AstNode* enVarStrengthRefp = new AstVarRef{fl, enVarStrengthp, VAccess::READ}; + + enp = (!enp) ? enVarStrengthRefp : new AstOr{fl, enp, enVarStrengthRefp}; + + beginStrength = endStrength; } + if (!outvarp) { // This is the final pre-forced resolution of the tristate, so we apply // the pull direction to any undriven pins. const AstPull* const pullp = static_cast(lhsp->user3p()); bool pull1 = pullp && pullp->direction() == 1; // Else default is down + + AstNode* undrivenp; + if (envarp) { + undrivenp = new AstNot{envarp->fileline(), + new AstVarRef{envarp->fileline(), envarp, VAccess::READ}}; + } else { + if (enp) { + undrivenp = new AstNot{enp->fileline(), enp}; + } else { + undrivenp = newAllZerosOrOnes(invarp, true); + } + } + undrivenp = new AstAnd{invarp->fileline(), undrivenp, newAllZerosOrOnes(invarp, pull1)}; - orp = new AstOr(invarp->fileline(), orp, undrivenp); - } else { - VL_DO_DANGLING(undrivenp->deleteTree(), undrivenp); + orp = new AstOr{invarp->fileline(), orp, undrivenp}; } + if (envarp) { - nodep->addStmtp(new AstAssignW( - enp->fileline(), new AstVarRef(envarp->fileline(), envarp, VAccess::WRITE), enp)); + AstAssignW* const enAssp = new AstAssignW{ + enp->fileline(), new AstVarRef{envarp->fileline(), envarp, VAccess::WRITE}, enp}; + if (debug() >= 9) enAssp->dumpTree(cout, "enAssp: "); + nodep->addStmtsp(enAssp); } + // __out (child) or (parent) = drive-value expression - AstNode* const assp = new AstAssignW( - lhsp->fileline(), new AstVarRef(lhsp->fileline(), lhsp, VAccess::WRITE), orp); + AstNode* const assp = new AstAssignW{ + lhsp->fileline(), new AstVarRef{lhsp->fileline(), lhsp, VAccess::WRITE}, orp}; assp->user2(U2_BOTH); // Don't process further; already resolved if (debug() >= 9) assp->dumpTree(cout, "-lhsp-eqn: "); - nodep->addStmtp(assp); + nodep->addStmtsp(assp); + } + + bool isOnlyAssignmentIsToLhsVar(AstAssignW* const nodep) { + if (AstVarRef* const varRefp = VN_CAST(nodep->lhsp(), VarRef)) { + auto foundIt = m_assigns.find(varRefp->varp()); + if (foundIt != m_assigns.end()) { + auto const& assignsToVar = foundIt->second; + if (assignsToVar.size() == 1 && assignsToVar[0] == nodep) return true; + } + } + return false; + } + + void addToAssignmentList(AstAssignW* nodep) { + if (AstVarRef* const varRefp = VN_CAST(nodep->lhsp(), VarRef)) { + if (varRefp->varp()->isNet()) { + m_assigns[varRefp->varp()].push_back(nodep); + } else if (nodep->strengthSpecp()) { + if (!varRefp->varp()->isNet()) + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Signal strengths are unsupported " + "on the following variable type: " + << varRefp->varp()->varType()); + + nodep->strengthSpecp()->unlinkFrBack()->deleteTree(); + } + } else if (nodep->strengthSpecp()) { + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: Assignments with signal strength with LHS of type: " + << nodep->lhsp()->prettyTypeName()); + } + } + + uint8_t getStrength(AstAssignW* const nodep, bool value) { + if (AstStrengthSpec* const strengthSpec = nodep->strengthSpecp()) { + return value ? strengthSpec->strength1() : strengthSpec->strength0(); + } + return VStrength::STRONG; // default strength is strong + } + + bool assignmentOfValueOnAllBits(AstAssignW* const nodep, bool value) { + if (AstConst* const constp = VN_CAST(nodep->rhsp(), Const)) { + const V3Number num = constp->num(); + return value ? num.isEqAllOnes() : num.isEqZero(); + } + return false; + } + + AstAssignW* getStrongestAssignmentOfValue(const Assigns& assigns, bool value) { + auto maxIt = std::max_element( + assigns.begin(), assigns.end(), [&](AstAssignW* ap, AstAssignW* bp) { + bool valuesOnRhsA = assignmentOfValueOnAllBits(ap, value); + bool valuesOnRhsB = assignmentOfValueOnAllBits(bp, value); + if (!valuesOnRhsA) return valuesOnRhsB; + if (!valuesOnRhsB) return false; + return getStrength(ap, value) < getStrength(bp, value); + }); + // If not all assignments have const with all bits equal to value on the RHS, + // std::max_element will return one of them anyway, so it has to be checked before + // returning + return assignmentOfValueOnAllBits(*maxIt, value) ? *maxIt : nullptr; + } + + bool isAssignmentNotStrongerThanStrength(AstAssignW* assignp, uint8_t strength) { + // If the value of the RHS is known and has all bits equal, only strength corresponding to + // its value is taken into account. In opposite case, both strengths are compared. + const uint8_t strength0 = getStrength(assignp, 0); + const uint8_t strength1 = getStrength(assignp, 1); + return (strength0 <= strength && strength1 <= strength) + || (strength0 <= strength && assignmentOfValueOnAllBits(assignp, 0)) + || (strength1 <= strength && assignmentOfValueOnAllBits(assignp, 1)); + } + + void removeNotStrongerAssignments(Assigns& assigns, AstAssignW* strongestp, + uint8_t greatestKnownStrength) { + // Weaker assignments are these assignments that can't change the final value of the net. + // They can be safely removed. Assignments of the same strength are also removed, because + // duplicates aren't needed. One problem is with 2 assignments of different values and + // equal strengths. It should result in assignment of x value, but these values aren't + // supported now. + auto removedIt = std::remove_if(assigns.begin(), assigns.end(), [&](AstAssignW* assignp) { + if (assignp == strongestp) return false; + if (isAssignmentNotStrongerThanStrength(assignp, greatestKnownStrength)) { + // Vertices corresponding to nodes from removed assignment's subtree have to be + // removed. + m_tgraph.deleteVerticesFromSubtreeRecurse(assignp); + VL_DO_DANGLING(pushDeletep(assignp->unlinkFrBack()), assignp); + return true; + } + return false; + }); + assigns.erase(removedIt, assigns.end()); + } + + void removeAssignmentsNotStrongerThanUniformConstant() { + // If a stronger assignment of a constant with all bits equal to the same + // value (0 or 1), is found, all weaker assignments can be safely removed. + for (auto& varpAssigns : m_assigns) { + Assigns& assigns = varpAssigns.second; + if (assigns.size() > 1) { + AstAssignW* const strongest0p = getStrongestAssignmentOfValue(assigns, 0); + AstAssignW* const strongest1p = getStrongestAssignmentOfValue(assigns, 1); + AstAssignW* strongestp = nullptr; + uint8_t greatestKnownStrength = 0; + const auto getIfStrongest + = [&](AstAssignW* const strongestCandidatep, bool value) { + if (!strongestCandidatep) return; + uint8_t strength = getStrength(strongestCandidatep, value); + if (strength >= greatestKnownStrength) { + greatestKnownStrength = strength; + strongestp = strongestCandidatep; + } + }; + getIfStrongest(strongest0p, 0); + getIfStrongest(strongest1p, 1); + + if (strongestp) { + removeNotStrongerAssignments(assigns, strongestp, greatestKnownStrength); + } + } + } + } + + void removeAssignmentsNotStrongerThanNonTristate() { + // Similar function as removeAssignmentsNotStrongerThanUniformConstant, but here the + // assignments that have strength not stronger than the strongest assignment with + // non-tristate RHS are removed. Strengths are compared according to their smaller values, + // because the values of RHSs are unknown. (Assignments not stronger than strongest + // constant are already removed.) + for (auto& varpAssigns : m_assigns) { + Assigns& assigns = varpAssigns.second; + if (assigns.size() > 1) { + auto maxIt = std::max_element( + assigns.begin(), assigns.end(), [&](AstAssignW* ap, AstAssignW* bp) { + if (m_tgraph.isTristate(ap)) return !m_tgraph.isTristate(bp); + if (m_tgraph.isTristate(bp)) return false; + const uint8_t minStrengthA + = std::min(getStrength(ap, 0), getStrength(ap, 1)); + const uint8_t minStrengthB + = std::min(getStrength(bp, 0), getStrength(bp, 1)); + return minStrengthA < minStrengthB; + }); + // If RHSs of all assignments are tristate, 1st element is returned, so it is + // needed to check if it is non-tristate. + AstAssignW* const strongestp = m_tgraph.isTristate(*maxIt) ? nullptr : *maxIt; + if (strongestp) { + uint8_t greatestKnownStrength + = std::min(getStrength(strongestp, 0), getStrength(strongestp, 1)); + removeNotStrongerAssignments(assigns, strongestp, greatestKnownStrength); + } + } + } } // VISITORS - virtual void visit(AstConst* nodep) override { + void visit(AstConst* nodep) override { UINFO(9, dbgState() << nodep << endl); if (m_graphing) { if (!m_alhs && nodep->num().hasZ()) m_tgraph.setTristate(nodep); @@ -670,15 +974,15 @@ class TristateVisitor final : public TristateBaseVisitor { } } - virtual void visit(AstCond* nodep) override { + void visit(AstCond* nodep) override { if (m_graphing) { iterateChildren(nodep); if (m_alhs) { - associateLogic(nodep, nodep->expr1p()); - associateLogic(nodep, nodep->expr2p()); + associateLogic(nodep, nodep->thenp()); + associateLogic(nodep, nodep->elsep()); } else { - associateLogic(nodep->expr1p(), nodep); - associateLogic(nodep->expr2p(), nodep); + associateLogic(nodep->thenp(), nodep); + associateLogic(nodep->elsep(), nodep); } } else { if (m_alhs && nodep->user1p()) { @@ -697,25 +1001,25 @@ class TristateVisitor final : public TristateBaseVisitor { condp->v3warn(E_UNSUPPORTED, "Unsupported: don't know how to deal with " "tristate logic in the conditional expression"); } - AstNode* const expr1p = nodep->expr1p(); - AstNode* const expr2p = nodep->expr2p(); - if (expr1p->user1p() || expr2p->user1p()) { // else no tristates + AstNode* const thenp = nodep->thenp(); + AstNode* const elsep = nodep->elsep(); + if (thenp->user1p() || elsep->user1p()) { // else no tristates m_tgraph.didProcess(nodep); - AstNode* const en1p = getEnp(expr1p); - AstNode* const en2p = getEnp(expr2p); + AstNode* const en1p = getEnp(thenp); + AstNode* const en2p = getEnp(elsep); // The output enable of a cond is a cond of the output enable of the // two expressions with the same conditional. AstNode* const enp = new AstCond(nodep->fileline(), condp->cloneTree(false), en1p, en2p); UINFO(9, " newcond " << enp << endl); nodep->user1p(enp); // propagate up COND(lhsp->enable, rhsp->enable) - expr1p->user1p(nullptr); - expr2p->user1p(nullptr); + thenp->user1p(nullptr); + elsep->user1p(nullptr); } } } - virtual void visit(AstSel* nodep) override { + void visit(AstSel* nodep) override { if (m_graphing) { iterateChildren(nodep); if (m_alhs) { @@ -754,7 +1058,7 @@ class TristateVisitor final : public TristateBaseVisitor { } } - virtual void visit(AstConcat* nodep) override { + void visit(AstConcat* nodep) override { if (m_graphing) { iterateChildren(nodep); if (m_alhs) { @@ -800,7 +1104,7 @@ class TristateVisitor final : public TristateBaseVisitor { } } - virtual void visit(AstBufIf1* nodep) override { + void visit(AstBufIf1* nodep) override { // For BufIf1, the enable is the LHS expression iterateChildren(nodep); UINFO(9, dbgState() << nodep << endl); @@ -884,11 +1188,13 @@ class TristateVisitor final : public TristateBaseVisitor { expr2p->user1p(nullptr); } } - virtual void visit(AstAnd* nodep) override { visitAndOr(nodep, true); } - virtual void visit(AstOr* nodep) override { visitAndOr(nodep, false); } + void visit(AstAnd* nodep) override { visitAndOr(nodep, true); } + void visit(AstOr* nodep) override { visitAndOr(nodep, false); } void visitAssign(AstNodeAssign* nodep) { if (m_graphing) { + if (AstAssignW* assignWp = VN_CAST(nodep, AssignW)) addToAssignmentList(assignWp); + if (nodep->user2() & U2_GRAPHING) return; VL_RESTORER(m_logicp); m_logicp = nodep; @@ -918,12 +1224,31 @@ class TristateVisitor final : public TristateBaseVisitor { m_tgraph.didProcess(nodep); } m_alhs = true; // And user1p() will indicate tristate equation, if any + if (AstAssignW* const assignWp = VN_CAST(nodep, AssignW)) { + if (AstStrengthSpec* const specp = assignWp->strengthSpecp()) { + if (specp->strength0() != specp->strength1()) { + // Unequal strengths are not a problem if the assignment is the only + // assignment to its variable. Unfortunately, m_assigns map stores only + // assignments to var. Selects are not inserted, so they may be handled + // improperly + if (!isOnlyAssignmentIsToLhsVar(assignWp)) { + assignWp->v3warn( + E_UNSUPPORTED, + "Unsupported: Unable to resolve unequal strength specifier"); + } + } else { + m_currentStrength = specp->strength0(); + } + } + } iterateAndNextNull(nodep->lhsp()); + // back to default strength + m_currentStrength = VStrength::STRONG; m_alhs = false; } } - virtual void visit(AstAssignW* nodep) override { visitAssign(nodep); } - virtual void visit(AstAssign* nodep) override { visitAssign(nodep); } + void visit(AstAssignW* nodep) override { visitAssign(nodep); } + void visit(AstAssign* nodep) override { visitAssign(nodep); } void visitCaseEq(AstNodeBiop* nodep, bool neq) { if (m_graphing) { @@ -993,12 +1318,12 @@ class TristateVisitor final : public TristateBaseVisitor { return; } } - virtual void visit(AstEqCase* nodep) override { visitCaseEq(nodep, false); } - virtual void visit(AstNeqCase* nodep) override { visitCaseEq(nodep, true); } - virtual void visit(AstEqWild* nodep) override { visitEqNeqWild(nodep); } - virtual void visit(AstNeqWild* nodep) override { visitEqNeqWild(nodep); } + void visit(AstEqCase* nodep) override { visitCaseEq(nodep, false); } + void visit(AstNeqCase* nodep) override { visitCaseEq(nodep, true); } + void visit(AstEqWild* nodep) override { visitEqNeqWild(nodep); } + void visit(AstNeqWild* nodep) override { visitEqNeqWild(nodep); } - virtual void visit(AstCountBits* nodep) override { + void visit(AstCountBits* nodep) override { std::array dropop; dropop[0] = VN_IS(nodep->rhsp(), Const) && VN_AS(nodep->rhsp(), Const)->num().isAnyZ(); dropop[1] = VN_IS(nodep->thsp(), Const) && VN_AS(nodep->thsp(), Const)->num().isAnyZ(); @@ -1058,7 +1383,7 @@ class TristateVisitor final : public TristateBaseVisitor { iterateChildren(nodep); } } - virtual void visit(AstPull* nodep) override { + void visit(AstPull* nodep) override { UINFO(9, dbgState() << nodep << endl); AstVarRef* varrefp = nullptr; if (VN_IS(nodep->lhsp(), VarRef)) { @@ -1133,7 +1458,7 @@ class TristateVisitor final : public TristateBaseVisitor { // __out(to-resolver-only) // const inout Spec says illegal // const output Unsupported; Illegal? - virtual void visit(AstPin* nodep) override { + void visit(AstPin* nodep) override { if (m_graphing) { if (nodep->user2() & U2_GRAPHING) return; // This pin is already expanded nodep->user2(U2_GRAPHING); @@ -1199,7 +1524,7 @@ class TristateVisitor final : public TristateBaseVisitor { UINFO(9, " newpin " << enpinp << endl); enpinp->user2(U2_BOTH); // don't iterate the pin later nodep->addNextHere(enpinp); - m_modp->addStmtp(enVarp); + m_modp->addStmtsp(enVarp); enrefp = new AstVarRef(nodep->fileline(), enVarp, VAccess::READ); UINFO(9, " newvrf " << enrefp << endl); if (debug() >= 9) enpinp->dumpTree(cout, "-pin-ena: "); @@ -1302,7 +1627,7 @@ class TristateVisitor final : public TristateBaseVisitor { } } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { UINFO(9, dbgState() << nodep << endl); if (m_graphing) { if (nodep->access().isWriteOrRW()) associateLogic(nodep, nodep->varp()); @@ -1334,7 +1659,7 @@ class TristateVisitor final : public TristateBaseVisitor { } } - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { iterateChildren(nodep); UINFO(9, dbgState() << nodep << endl); if (m_graphing) { @@ -1367,12 +1692,13 @@ class TristateVisitor final : public TristateBaseVisitor { } } - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { UINFO(8, nodep << endl); VL_RESTORER(m_modp); VL_RESTORER(m_graphing); VL_RESTORER(m_unique); VL_RESTORER(m_lhsmap); + VL_RESTORER(m_assigns); // Not preserved, needs pointer instead: TristateGraph origTgraph = m_tgraph; UASSERT_OBJ(m_tgraph.empty(), nodep, "Unsupported: NodeModule under NodeModule"); { @@ -1382,6 +1708,7 @@ class TristateVisitor final : public TristateBaseVisitor { m_unique = 0; m_logicp = nullptr; m_lhsmap.clear(); + m_assigns.clear(); m_modp = nodep; // Walk the graph, finding all variables and tristate constructs { @@ -1389,8 +1716,14 @@ class TristateVisitor final : public TristateBaseVisitor { iterateChildren(nodep); m_graphing = false; } + // Remove all assignments not stronger than the strongest uniform constant + removeAssignmentsNotStrongerThanUniformConstant(); // Use graph to find tristate signals m_tgraph.graphWalk(nodep); + + // Remove all assignments not stronger than the strongest non-tristate RHS + removeAssignmentsNotStrongerThanNonTristate(); + // Build the LHS drivers map for this module iterateChildren(nodep); // Insert new logic for all tristates @@ -1399,29 +1732,29 @@ class TristateVisitor final : public TristateBaseVisitor { m_tgraph.clear(); // Recursion not supported } - virtual void visit(AstClass* nodep) override { + void visit(AstClass* nodep) override { // don't deal with classes } - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstNodeFTask* nodep) override { // don't deal with functions } - virtual void visit(AstCaseItem* nodep) override { + void visit(AstCaseItem* nodep) override { // don't deal with casez compare '???? values - iterateAndNextNull(nodep->bodysp()); + iterateAndNextNull(nodep->stmtsp()); } - virtual void visit(AstCell* nodep) override { + void visit(AstCell* nodep) override { VL_RESTORER(m_cellp); m_cellp = nodep; m_alhs = false; iterateChildren(nodep); } - virtual void visit(AstNetlist* nodep) override { iterateChildrenBackwards(nodep); } + void visit(AstNetlist* nodep) override { iterateChildrenBackwards(nodep); } // Default: Just iterate - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { iterateChildren(nodep); checkUnhandled(nodep); } @@ -1432,7 +1765,7 @@ public: m_tgraph.clear(); iterate(nodep); } - virtual ~TristateVisitor() override { + ~TristateVisitor() override { V3Stats::addStat("Tristate, Tristate resolved nets", m_statTriSigs); } }; @@ -1443,5 +1776,5 @@ public: void V3Tristate::tristateAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { TristateVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("tristate", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("tristate", 0, dumpTree() >= 3); } diff --git a/src/V3Undriven.cpp b/src/V3Undriven.cpp index 0732dafa1..716005892 100644 --- a/src/V3Undriven.cpp +++ b/src/V3Undriven.cpp @@ -30,11 +30,14 @@ #include "V3Ast.h" #include "V3Global.h" +#include "V3Stats.h" #include "V3String.h" #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Class for every variable we may process @@ -46,8 +49,6 @@ class UndrivenVarEntry final { enum : uint8_t { FLAG_USED = 0, FLAG_DRIVEN = 1, FLAGS_PER_BIT = 2 }; - VL_DEBUG_FUNC; // Declare debug() - public: // CONSTRUCTORS explicit UndrivenVarEntry(AstVar* varp) @@ -256,7 +257,6 @@ private: const AstAlways* m_alwaysCombp = nullptr; // Current always if combo, otherwise nullptr // METHODS - VL_DEBUG_FUNC; // Declare debug() UndrivenVarEntry* getEntryp(AstVar* nodep, int which_user) { if (!(which_user == 1 ? nodep->user1p() : nodep->user2p())) { @@ -293,7 +293,7 @@ private: } // VISITORS - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { for (int usr = 1; usr < (m_alwaysCombp ? 3 : 2); ++usr) { // For assigns and non-combo always, do just usr==1, to look // for module-wide undriven etc. @@ -314,15 +314,15 @@ private: // Discover variables used in bit definitions, etc iterateChildren(nodep); } - virtual void visit(AstArraySel* nodep) override { + void visit(AstArraySel* nodep) override { // Arrays are rarely constant assigned, so for now we punt and do all entries iterateChildren(nodep); } - virtual void visit(AstSliceSel* nodep) override { + void visit(AstSliceSel* nodep) override { // Arrays are rarely constant assigned, so for now we punt and do all entries iterateChildren(nodep); } - virtual void visit(AstSel* nodep) override { + void visit(AstSel* nodep) override { AstNodeVarRef* const varrefp = VN_CAST(nodep->fromp(), NodeVarRef); AstConst* const constp = VN_CAST(nodep->lsbp(), Const); if (varrefp && constp && !constp->num().isFourState()) { @@ -346,7 +346,7 @@ private: iterateChildren(nodep); } } - virtual void visit(AstNodeVarRef* nodep) override { + void visit(AstNodeVarRef* nodep) override { // Any variable if (nodep->access().isWriteOrRW() && !VN_IS(nodep, VarXRef)) { // Ignore interface variables and similar ugly items @@ -387,7 +387,7 @@ private: } // Don't know what black boxed calls do, assume in+out - virtual void visit(AstSysIgnore* nodep) override { + void visit(AstSysIgnore* nodep) override { VL_RESTORER(m_inBBox); { m_inBBox = true; @@ -395,28 +395,28 @@ private: } } - virtual void visit(AstAssign* nodep) override { + void visit(AstAssign* nodep) override { VL_RESTORER(m_inProcAssign); { m_inProcAssign = true; iterateChildren(nodep); } } - virtual void visit(AstAssignDly* nodep) override { + void visit(AstAssignDly* nodep) override { VL_RESTORER(m_inProcAssign); { m_inProcAssign = true; iterateChildren(nodep); } } - virtual void visit(AstAssignW* nodep) override { + void visit(AstAssignW* nodep) override { VL_RESTORER(m_inContAssign); { m_inContAssign = true; iterateChildren(nodep); } } - virtual void visit(AstAlways* nodep) override { + void visit(AstAlways* nodep) override { VL_RESTORER(m_alwaysCombp); { AstNode::user2ClearTree(); @@ -431,37 +431,37 @@ private: } } - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstNodeFTask* nodep) override { VL_RESTORER(m_taskp); { m_taskp = nodep; iterateChildren(nodep); } } - virtual void visit(AstPin* nodep) override { + void visit(AstPin* nodep) override { VL_RESTORER(m_inInoutPin); m_inInoutPin = nodep->modVarp()->isInoutish(); iterateChildren(nodep); } // Until we support tables, primitives will have undriven and unused I/Os - virtual void visit(AstPrimitive*) override {} + void visit(AstPrimitive*) override {} // Coverage artifacts etc shouldn't count as a sink - virtual void visit(AstCoverDecl*) override {} - virtual void visit(AstCoverInc*) override {} - virtual void visit(AstCoverToggle*) override {} - virtual void visit(AstTraceDecl*) override {} - virtual void visit(AstTraceInc*) override {} + void visit(AstCoverDecl*) override {} + void visit(AstCoverInc*) override {} + void visit(AstCoverToggle*) override {} + void visit(AstTraceDecl*) override {} + void visit(AstTraceInc*) override {} // iterate - virtual void visit(AstConst* nodep) override {} - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstConst* nodep) override {} + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit UndrivenVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~UndrivenVisitor() override { + ~UndrivenVisitor() override { for (UndrivenVarEntry* ip : m_entryps[1]) ip->reportViolations(); for (int usr = 1; usr < 3; ++usr) { for (UndrivenVarEntry* ip : m_entryps[usr]) delete ip; @@ -475,4 +475,5 @@ public: void V3Undriven::undrivenAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { UndrivenVisitor{nodep}; } + if (v3Global.opt.stats()) V3Stats::statsStage("undriven"); } diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp index 12f011366..22a10af7d 100644 --- a/src/V3Unknown.cpp +++ b/src/V3Unknown.cpp @@ -41,6 +41,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### class UnknownVisitor final : public VNVisitor { @@ -64,7 +66,6 @@ private: V3UniqueNames m_xrandNames; // For generating unique temporary variable names // METHODS - VL_DEBUG_FUNC; // Declare debug() void replaceBoundLvalue(AstNode* nodep, AstNode* condp) { // Spec says a out-of-range LHS SEL results in a NOP. @@ -120,7 +121,7 @@ private: } else { AstVar* const varp = new AstVar(fl, VVarType::MODULETEMP, m_lvboundNames.get(prep), prep->dtypep()); - m_modp->addStmtp(varp); + m_modp->addStmtsp(varp); AstNode* const abovep = prep->backp(); // Grab above point before we replace 'prep' prep->replaceWith(new AstVarRef(fl, varp, VAccess::WRITE)); AstIf* const newp = new AstIf( @@ -138,7 +139,7 @@ private: } // VISITORS - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { UINFO(4, " MOD " << nodep << endl); VL_RESTORER(m_modp); VL_RESTORER(m_constXCvt); @@ -153,30 +154,30 @@ private: iterateChildren(nodep); } } - virtual void visit(AstAssignDly* nodep) override { + void visit(AstAssignDly* nodep) override { VL_RESTORER(m_assigndlyp); { m_assigndlyp = nodep; VL_DO_DANGLING(iterateChildren(nodep), nodep); // May delete nodep. } } - virtual void visit(AstAssignW* nodep) override { + void visit(AstAssignW* nodep) override { VL_RESTORER(m_assignwp); { m_assignwp = nodep; VL_DO_DANGLING(iterateChildren(nodep), nodep); // May delete nodep. } } - virtual void visit(AstCaseItem* nodep) override { + void visit(AstCaseItem* nodep) override { VL_RESTORER(m_constXCvt); { m_constXCvt = false; // Avoid losing the X's in casex iterateAndNextNull(nodep->condsp()); m_constXCvt = true; - iterateAndNextNull(nodep->bodysp()); + iterateAndNextNull(nodep->stmtsp()); } } - virtual void visit(AstNodeDType* nodep) override { + void visit(AstNodeDType* nodep) override { VL_RESTORER(m_constXCvt); { m_constXCvt = false; // Avoid losing the X's in casex @@ -255,11 +256,11 @@ private: } } - virtual void visit(AstEqCase* nodep) override { visitEqNeqCase(nodep); } - virtual void visit(AstNeqCase* nodep) override { visitEqNeqCase(nodep); } - virtual void visit(AstEqWild* nodep) override { visitEqNeqWild(nodep); } - virtual void visit(AstNeqWild* nodep) override { visitEqNeqWild(nodep); } - virtual void visit(AstIsUnknown* nodep) override { + void visit(AstEqCase* nodep) override { visitEqNeqCase(nodep); } + void visit(AstNeqCase* nodep) override { visitEqNeqCase(nodep); } + void visit(AstEqWild* nodep) override { visitEqNeqWild(nodep); } + void visit(AstNeqWild* nodep) override { visitEqNeqWild(nodep); } + void visit(AstIsUnknown* nodep) override { iterateChildren(nodep); // Ahh, we're two state, so this is easy UINFO(4, " ISUNKNOWN->0 " << nodep << endl); @@ -267,7 +268,7 @@ private: nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } - virtual void visit(AstCountBits* nodep) override { + void visit(AstCountBits* nodep) override { // Ahh, we're two state, so this is easy std::array dropop; dropop[0] = VN_IS(nodep->rhsp(), Const) && VN_AS(nodep->rhsp(), Const)->num().isAnyX(); @@ -303,7 +304,7 @@ private: } iterateChildren(nodep); } - virtual void visit(AstConst* nodep) override { + void visit(AstConst* nodep) override { if (m_constXCvt && nodep->num().isFourState()) { UINFO(4, " CONST4 " << nodep << endl); if (debug() >= 9) nodep->dumpTree(cout, " Const_old: "); @@ -331,8 +332,8 @@ private: // We use the special XTEMP type so it doesn't break pure functions UASSERT_OBJ(m_modp, nodep, "X number not under module"); AstVar* const newvarp - = new AstVar(nodep->fileline(), VVarType::XTEMP, m_xrandNames.get(nodep), - VFlagLogicPacked(), nodep->width()); + = new AstVar{nodep->fileline(), VVarType::XTEMP, m_xrandNames.get(nodep), + VFlagLogicPacked{}, nodep->width()}; newvarp->lifetime(VLifetime::STATIC); ++m_statUnkVars; VNRelinker replaceHandle; @@ -353,9 +354,9 @@ private: // Add inits in front of other statement. // In the future, we should stuff the initp into the module's constructor. AstNode* const afterp = m_modp->stmtsp()->unlinkFrBackWithNext(); - m_modp->addStmtp(newvarp); - m_modp->addStmtp(newinitp); - m_modp->addStmtp(afterp); + m_modp->addStmtsp(newvarp); + m_modp->addStmtsp(newinitp); + m_modp->addStmtsp(afterp); if (debug() >= 9) newref1p->dumpTree(cout, " _new: "); if (debug() >= 9) newvarp->dumpTree(cout, " _new: "); if (debug() >= 9) newinitp->dumpTree(cout, " _new: "); @@ -364,7 +365,7 @@ private: } } - virtual void visit(AstSel* nodep) override { + void visit(AstSel* nodep) override { iterateChildren(nodep); if (!nodep->user1SetOnce()) { // Guard against reading/writing past end of bit vector array @@ -411,7 +412,7 @@ private: // visit(AstSliceSel) not needed as its bounds are constant and checked // in V3Width. - virtual void visit(AstArraySel* nodep) override { + void visit(AstArraySel* nodep) override { iterateChildren(nodep); if (!nodep->user1SetOnce()) { if (debug() == 9) nodep->dumpTree(cout, "-in: "); @@ -454,7 +455,7 @@ private: nodep->unlinkFrBack(&replaceHandle); V3Number xnum(nodep, nodep->width()); if (nodep->isString()) { - xnum = V3Number(V3Number::String(), nodep, ""); + xnum = V3Number{V3Number::String{}, nodep, ""}; } else { xnum.setAllBitsX(); } @@ -482,7 +483,7 @@ private: } } //-------------------- - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS @@ -491,7 +492,7 @@ public: , m_xrandNames{"__Vxrand"} { iterate(nodep); } - virtual ~UnknownVisitor() override { // + ~UnknownVisitor() override { // V3Stats::addStat("Unknowns, variables created", m_statUnkVars); } }; @@ -502,5 +503,5 @@ public: void V3Unknown::unknownAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { UnknownVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("unknown", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("unknown", 0, dumpTree() >= 3); } diff --git a/src/V3Unroll.cpp b/src/V3Unroll.cpp index 0b47ce518..4629f16a5 100644 --- a/src/V3Unroll.cpp +++ b/src/V3Unroll.cpp @@ -37,6 +37,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Unroll state, as a visitor of each AstNode @@ -57,7 +59,6 @@ private: VDouble0 m_statIters; // Statistic tracking // METHODS - VL_DEBUG_FUNC; // Declare debug() // VISITORS bool cantUnroll(AstNode* nodep, const char* reason) const { @@ -279,15 +280,15 @@ private: } if (precondsp) { precondsp->unlinkFrBackWithNext(); - stmtsp = AstNode::addNextNull(stmtsp, precondsp); + stmtsp = AstNode::addNext(stmtsp, precondsp); } if (bodysp) { bodysp->unlinkFrBackWithNext(); - stmtsp = AstNode::addNextNull(stmtsp, bodysp); // Maybe null if no body + stmtsp = AstNode::addNext(stmtsp, bodysp); // Maybe null if no body } if (incp && !VN_IS(nodep, GenFor)) { // Generates don't need to increment loop index incp->unlinkFrBackWithNext(); - stmtsp = AstNode::addNextNull(stmtsp, incp); // Maybe null if no body + stmtsp = AstNode::addNext(stmtsp, incp); // Maybe null if no body } // Mark variable to disable some later warnings m_forVarp->usedLoopIdx(true); @@ -371,7 +372,7 @@ private: return true; } - virtual void visit(AstWhile* nodep) override { + void visit(AstWhile* nodep) override { iterateChildren(nodep); if (m_varModeCheck || m_varModeReplace) { } else { @@ -387,26 +388,26 @@ private: if (nodep->backp()->nextp() == nodep) initp = nodep->backp(); // Grab assignment AstNode* incp = nullptr; // Should be last statement - AstNode* bodysp = nodep->bodysp(); + AstNode* stmtsp = nodep->stmtsp(); if (nodep->incsp()) V3Const::constifyEdit(nodep->incsp()); // cppcheck-suppress duplicateCondition if (nodep->incsp()) { incp = nodep->incsp(); } else { - for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {} + for (incp = nodep->stmtsp(); incp && incp->nextp(); incp = incp->nextp()) {} if (incp) VL_DO_DANGLING(V3Const::constifyEdit(incp), incp); // Again, as may have changed - bodysp = nodep->bodysp(); - for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {} - if (incp == bodysp) bodysp = nullptr; + stmtsp = nodep->stmtsp(); + for (incp = nodep->stmtsp(); incp && incp->nextp(); incp = incp->nextp()) {} + if (incp == stmtsp) stmtsp = nullptr; } // And check it - if (forUnrollCheck(nodep, initp, nodep->precondsp(), nodep->condp(), incp, bodysp)) { + if (forUnrollCheck(nodep, initp, nodep->precondsp(), nodep->condp(), incp, stmtsp)) { VL_DO_DANGLING(pushDeletep(nodep), nodep); // Did replacement } } } - virtual void visit(AstGenFor* nodep) override { + void visit(AstGenFor* nodep) override { if (!m_generate || m_varModeReplace) { iterateChildren(nodep); } // else V3Param will recursively call each for loop to be unrolled for us @@ -426,14 +427,14 @@ private: // deleted by V3Const. VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); } else if (forUnrollCheck(nodep, nodep->initsp(), nullptr, nodep->condp(), - nodep->incsp(), nodep->bodysp())) { + nodep->incsp(), nodep->stmtsp())) { VL_DO_DANGLING(pushDeletep(nodep), nodep); // Did replacement } else { nodep->v3error("For loop doesn't have genvar index, or is malformed"); } } } - virtual void visit(AstNodeFor* nodep) override { + void visit(AstNodeFor* nodep) override { if (m_generate) { // Ignore for's when expanding genfor's iterateChildren(nodep); } else { @@ -441,7 +442,7 @@ private: } } - virtual void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) override { if (m_varModeCheck && nodep->varp() == m_forVarp && nodep->varScopep() == m_forVscp && nodep->access().isWriteOrRW()) { UINFO(8, " Itervar assigned to: " << nodep << endl); @@ -458,7 +459,7 @@ private: //-------------------- // Default: Just iterate - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { if (m_varModeCheck && nodep == m_ignoreIncp) { // Ignore subtree that is the increment } else { @@ -469,7 +470,7 @@ private: public: // CONSTRUCTORS UnrollVisitor() { init(false, ""); } - virtual ~UnrollVisitor() override { + ~UnrollVisitor() override { V3Stats::addStatSum("Optimizations, Unrolled Loops", m_statLoops); V3Stats::addStatSum("Optimizations, Unrolled Iterations", m_statIters); } @@ -517,5 +518,5 @@ void V3Unroll::unrollAll(AstNetlist* nodep) { UnrollStateful unroller; unroller.unrollAll(nodep); } // Destruct before checking - V3Global::dumpCheckGlobalTree("unroll", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("unroll", 0, dumpTree() >= 3); } diff --git a/src/V3VariableOrder.cpp b/src/V3VariableOrder.cpp index d62cfb50f..562bc7225 100644 --- a/src/V3VariableOrder.cpp +++ b/src/V3VariableOrder.cpp @@ -34,6 +34,8 @@ #include #include +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Establish mtask variable sort order in mtasks mode @@ -51,15 +53,15 @@ public: } ~VarTspSorter() override = default; // METHODS - virtual bool operator<(const TspStateBase& other) const override { - return operator<(dynamic_cast(other)); + bool operator<(const TspStateBase& other) const override { + return operator<(static_cast(other)); } bool operator<(const VarTspSorter& other) const { return m_serial < other.m_serial; } const MTaskIdSet& mtaskIds() const { return m_mtaskIds; } - virtual int cost(const TspStateBase* otherp) const override { - return cost(dynamic_cast(otherp)); + int cost(const TspStateBase* otherp) const override { + return cost(static_cast(otherp)); } - virtual int cost(const VarTspSorter* otherp) const { + int cost(const VarTspSorter* otherp) const { int cost = diffs(m_mtaskIds, otherp->m_mtaskIds); cost += diffs(otherp->m_mtaskIds, m_mtaskIds); return cost; @@ -186,9 +188,9 @@ class VariableOrder final { for (; it != varps.cend(); ++it) firstp->addNext(*it); if (AstNode* const stmtsp = modp->stmtsp()) { stmtsp->unlinkFrBackWithNext(); - firstp->addNext(stmtsp); + AstNode::addNext(firstp, stmtsp); } - modp->addStmtp(firstp); + modp->addStmtsp(firstp); } } @@ -205,5 +207,5 @@ void V3VariableOrder::orderAll() { modp = VN_AS(modp->nextp(), NodeModule)) { VariableOrder::processModule(modp); } - V3Global::dumpCheckGlobalTree("variableorder", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("variableorder", 0, dumpTree() >= 3); } diff --git a/src/V3Waiver.cpp b/src/V3Waiver.cpp index 42d222fe8..41a07c1ff 100644 --- a/src/V3Waiver.cpp +++ b/src/V3Waiver.cpp @@ -6,9 +6,10 @@ // //************************************************************************* // -// Copyright 2020 by Wilson Snyder. This program is free software; you can -// redistribute it and/or modify it under the terms of either the GNU Lesser -// General Public License Version 3 or the Perl Artistic License Version 2.0. +// Copyright 2020-2022 by Wilson Snyder. This program is free software; you +// can redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 // //************************************************************************* diff --git a/src/V3Width.cpp b/src/V3Width.cpp index a9f784e06..040b5b2bf 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -81,6 +81,8 @@ #define VERILATOR_V3WIDTH_CPP_ #include "V3WidthCommit.h" +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### enum Stage : uint8_t { @@ -236,9 +238,6 @@ private: EXTEND_OFF // No extension }; - // METHODS - static int debug() { return V3Width::debug(); } - // VISITORS // Naming: width_O{outputtype}_L{lhstype}_R{rhstype}_W{widthing}_S{signing} // Where type: @@ -250,123 +249,119 @@ private: // _Ox=anything // Widths: 1 bit out, lhs 1 bit; Real: converts via compare with 0 - virtual void visit(AstLogNot* nodep) override { visit_log_not(nodep); } + void visit(AstLogNot* nodep) override { visit_log_not(nodep); } // Widths: 1 bit out, lhs 1 bit, rhs 1 bit; Real: converts via compare with 0 - virtual void visit(AstLogAnd* nodep) override { visit_log_and_or(nodep); } - virtual void visit(AstLogOr* nodep) override { visit_log_and_or(nodep); } - virtual void visit(AstLogEq* nodep) override { + void visit(AstLogAnd* nodep) override { visit_log_and_or(nodep); } + void visit(AstLogOr* nodep) override { visit_log_and_or(nodep); } + void visit(AstLogEq* nodep) override { // Conversion from real not in IEEE, but a fallout visit_log_and_or(nodep); } - virtual void visit(AstLogIf* nodep) override { + void visit(AstLogIf* nodep) override { // Conversion from real not in IEEE, but a fallout visit_log_and_or(nodep); } // Widths: 1 bit out, Any width lhs - virtual void visit(AstRedAnd* nodep) override { visit_red_and_or(nodep); } - virtual void visit(AstRedOr* nodep) override { visit_red_and_or(nodep); } - virtual void visit(AstRedXor* nodep) override { visit_red_and_or(nodep); } - virtual void visit(AstOneHot* nodep) override { visit_red_and_or(nodep); } - virtual void visit(AstOneHot0* nodep) override { visit_red_and_or(nodep); } - virtual void visit(AstIsUnknown* nodep) override { + void visit(AstRedAnd* nodep) override { visit_red_and_or(nodep); } + void visit(AstRedOr* nodep) override { visit_red_and_or(nodep); } + void visit(AstRedXor* nodep) override { visit_red_and_or(nodep); } + void visit(AstOneHot* nodep) override { visit_red_and_or(nodep); } + void visit(AstOneHot0* nodep) override { visit_red_and_or(nodep); } + void visit(AstIsUnknown* nodep) override { visit_red_unknown(nodep); // Allow real } // These have different node types, as they operate differently // Must add to case statement below, // Widths: 1 bit out, lhs width == rhs width. real if lhs|rhs real - virtual void visit(AstEq* nodep) override { visit_cmp_eq_gt(nodep, true); } - virtual void visit(AstNeq* nodep) override { visit_cmp_eq_gt(nodep, true); } - virtual void visit(AstGt* nodep) override { visit_cmp_eq_gt(nodep, true); } - virtual void visit(AstGte* nodep) override { visit_cmp_eq_gt(nodep, true); } - virtual void visit(AstLt* nodep) override { visit_cmp_eq_gt(nodep, true); } - virtual void visit(AstLte* nodep) override { visit_cmp_eq_gt(nodep, true); } - virtual void visit(AstGtS* nodep) override { visit_cmp_eq_gt(nodep, true); } - virtual void visit(AstGteS* nodep) override { visit_cmp_eq_gt(nodep, true); } - virtual void visit(AstLtS* nodep) override { visit_cmp_eq_gt(nodep, true); } - virtual void visit(AstLteS* nodep) override { visit_cmp_eq_gt(nodep, true); } - virtual void visit(AstEqCase* nodep) override { visit_cmp_eq_gt(nodep, true); } - virtual void visit(AstNeqCase* nodep) override { visit_cmp_eq_gt(nodep, true); } + void visit(AstEq* nodep) override { visit_cmp_eq_gt(nodep, true); } + void visit(AstNeq* nodep) override { visit_cmp_eq_gt(nodep, true); } + void visit(AstGt* nodep) override { visit_cmp_eq_gt(nodep, true); } + void visit(AstGte* nodep) override { visit_cmp_eq_gt(nodep, true); } + void visit(AstLt* nodep) override { visit_cmp_eq_gt(nodep, true); } + void visit(AstLte* nodep) override { visit_cmp_eq_gt(nodep, true); } + void visit(AstGtS* nodep) override { visit_cmp_eq_gt(nodep, true); } + void visit(AstGteS* nodep) override { visit_cmp_eq_gt(nodep, true); } + void visit(AstLtS* nodep) override { visit_cmp_eq_gt(nodep, true); } + void visit(AstLteS* nodep) override { visit_cmp_eq_gt(nodep, true); } + void visit(AstEqCase* nodep) override { visit_cmp_eq_gt(nodep, true); } + void visit(AstNeqCase* nodep) override { visit_cmp_eq_gt(nodep, true); } // ... These comparisons don't allow reals - virtual void visit(AstEqWild* nodep) override { visit_cmp_eq_gt(nodep, false); } - virtual void visit(AstNeqWild* nodep) override { visit_cmp_eq_gt(nodep, false); } + void visit(AstEqWild* nodep) override { visit_cmp_eq_gt(nodep, false); } + void visit(AstNeqWild* nodep) override { visit_cmp_eq_gt(nodep, false); } // ... Real compares - virtual void visit(AstEqD* nodep) override { visit_cmp_real(nodep); } - virtual void visit(AstNeqD* nodep) override { visit_cmp_real(nodep); } - virtual void visit(AstLtD* nodep) override { visit_cmp_real(nodep); } - virtual void visit(AstLteD* nodep) override { visit_cmp_real(nodep); } - virtual void visit(AstGtD* nodep) override { visit_cmp_real(nodep); } - virtual void visit(AstGteD* nodep) override { visit_cmp_real(nodep); } + void visit(AstEqD* nodep) override { visit_cmp_real(nodep); } + void visit(AstNeqD* nodep) override { visit_cmp_real(nodep); } + void visit(AstLtD* nodep) override { visit_cmp_real(nodep); } + void visit(AstLteD* nodep) override { visit_cmp_real(nodep); } + void visit(AstGtD* nodep) override { visit_cmp_real(nodep); } + void visit(AstGteD* nodep) override { visit_cmp_real(nodep); } // ... String compares - virtual void visit(AstEqN* nodep) override { visit_cmp_string(nodep); } - virtual void visit(AstNeqN* nodep) override { visit_cmp_string(nodep); } - virtual void visit(AstLtN* nodep) override { visit_cmp_string(nodep); } - virtual void visit(AstLteN* nodep) override { visit_cmp_string(nodep); } - virtual void visit(AstGtN* nodep) override { visit_cmp_string(nodep); } - virtual void visit(AstGteN* nodep) override { visit_cmp_string(nodep); } + void visit(AstEqN* nodep) override { visit_cmp_string(nodep); } + void visit(AstNeqN* nodep) override { visit_cmp_string(nodep); } + void visit(AstLtN* nodep) override { visit_cmp_string(nodep); } + void visit(AstLteN* nodep) override { visit_cmp_string(nodep); } + void visit(AstGtN* nodep) override { visit_cmp_string(nodep); } + void visit(AstGteN* nodep) override { visit_cmp_string(nodep); } // Widths: out width = lhs width = rhs width // Signed: Output signed iff LHS & RHS signed. // Real: Not allowed - virtual void visit(AstAnd* nodep) override { visit_boolmath_and_or(nodep); } - virtual void visit(AstOr* nodep) override { visit_boolmath_and_or(nodep); } - virtual void visit(AstXor* nodep) override { visit_boolmath_and_or(nodep); } - virtual void visit(AstBufIf1* nodep) override { + void visit(AstAnd* nodep) override { visit_boolmath_and_or(nodep); } + void visit(AstOr* nodep) override { visit_boolmath_and_or(nodep); } + void visit(AstXor* nodep) override { visit_boolmath_and_or(nodep); } + void visit(AstBufIf1* nodep) override { visit_boolmath_and_or(nodep); } // Signed behavior changing in 3.814 // Width: Max(Lhs,Rhs) sort of. // Real: If either side real // Signed: If both sides real - virtual void visit(AstAdd* nodep) override { visit_add_sub_replace(nodep, true); } - virtual void visit(AstSub* nodep) override { visit_add_sub_replace(nodep, true); } - virtual void visit(AstDiv* nodep) override { visit_add_sub_replace(nodep, true); } - virtual void visit(AstMul* nodep) override { visit_add_sub_replace(nodep, true); } + void visit(AstAdd* nodep) override { visit_add_sub_replace(nodep, true); } + void visit(AstSub* nodep) override { visit_add_sub_replace(nodep, true); } + void visit(AstDiv* nodep) override { visit_add_sub_replace(nodep, true); } + void visit(AstMul* nodep) override { visit_add_sub_replace(nodep, true); } // These can't promote to real - virtual void visit(AstModDiv* nodep) override { visit_add_sub_replace(nodep, false); } - virtual void visit(AstModDivS* nodep) override { visit_add_sub_replace(nodep, false); } - virtual void visit(AstMulS* nodep) override { visit_add_sub_replace(nodep, false); } - virtual void visit(AstDivS* nodep) override { visit_add_sub_replace(nodep, false); } + void visit(AstModDiv* nodep) override { visit_add_sub_replace(nodep, false); } + void visit(AstModDivS* nodep) override { visit_add_sub_replace(nodep, false); } + void visit(AstMulS* nodep) override { visit_add_sub_replace(nodep, false); } + void visit(AstDivS* nodep) override { visit_add_sub_replace(nodep, false); } // Widths: out width = lhs width, but upper matters // Signed: Output signed iff LHS signed; unary operator // Unary promote to real - virtual void visit(AstNegate* nodep) override { visit_negate_not(nodep, true); } + void visit(AstNegate* nodep) override { visit_negate_not(nodep, true); } // Unary never real - virtual void visit(AstNot* nodep) override { visit_negate_not(nodep, false); } + void visit(AstNot* nodep) override { visit_negate_not(nodep, false); } // Real: inputs and output real - virtual void visit(AstAddD* nodep) override { visit_real_add_sub(nodep); } - virtual void visit(AstSubD* nodep) override { visit_real_add_sub(nodep); } - virtual void visit(AstDivD* nodep) override { visit_real_add_sub(nodep); } - virtual void visit(AstMulD* nodep) override { visit_real_add_sub(nodep); } - virtual void visit(AstPowD* nodep) override { visit_real_add_sub(nodep); } - virtual void visit(AstNodeSystemBiop* nodep) override { visit_real_add_sub(nodep); } + void visit(AstAddD* nodep) override { visit_real_add_sub(nodep); } + void visit(AstSubD* nodep) override { visit_real_add_sub(nodep); } + void visit(AstDivD* nodep) override { visit_real_add_sub(nodep); } + void visit(AstMulD* nodep) override { visit_real_add_sub(nodep); } + void visit(AstPowD* nodep) override { visit_real_add_sub(nodep); } + void visit(AstNodeSystemBiop* nodep) override { visit_real_add_sub(nodep); } // Real: Output real - virtual void visit(AstNegateD* nodep) override { visit_real_neg_ceil(nodep); } - virtual void visit(AstNodeSystemUniop* nodep) override { visit_real_neg_ceil(nodep); } + void visit(AstNegateD* nodep) override { visit_real_neg_ceil(nodep); } + void visit(AstNodeSystemUniop* nodep) override { visit_real_neg_ceil(nodep); } // Widths: out signed/unsigned width = lhs width, input un|signed - virtual void visit(AstSigned* nodep) override { - visit_signed_unsigned(nodep, VSigning::SIGNED); - } - virtual void visit(AstUnsigned* nodep) override { - visit_signed_unsigned(nodep, VSigning::UNSIGNED); - } + void visit(AstSigned* nodep) override { visit_signed_unsigned(nodep, VSigning::SIGNED); } + void visit(AstUnsigned* nodep) override { visit_signed_unsigned(nodep, VSigning::UNSIGNED); } // Widths: Output width from lhs, rhs<33 bits // Signed: If lhs signed - virtual void visit(AstShiftL* nodep) override { visit_shift(nodep); } - virtual void visit(AstShiftR* nodep) override { visit_shift(nodep); } + void visit(AstShiftL* nodep) override { visit_shift(nodep); } + void visit(AstShiftR* nodep) override { visit_shift(nodep); } // ShiftRS converts to ShiftR, but not vice-versa - virtual void visit(AstShiftRS* nodep) override { visit_shift(nodep); } + void visit(AstShiftRS* nodep) override { visit_shift(nodep); } //======== // Widths: Output real, input integer signed - virtual void visit(AstBitsToRealD* nodep) override { visit_Or_Lu64(nodep); } + void visit(AstBitsToRealD* nodep) override { visit_Or_Lu64(nodep); } // Widths: Output integer signed, input real - virtual void visit(AstRToIS* nodep) override { visit_Os32_Lr(nodep); } - virtual void visit(AstRToIRoundS* nodep) override { + void visit(AstRToIS* nodep) override { visit_Os32_Lr(nodep); } + void visit(AstRToIRoundS* nodep) override { // Only created here, size comes from upper expression if (m_vup->prelim()) { // First stage evaluation iterateCheckReal(nodep, "LHS", nodep->lhsp(), BOTH); @@ -375,11 +370,11 @@ private: } // Widths: Output integer unsigned, input real - virtual void visit(AstRealToBits* nodep) override { visit_Ou64_Lr(nodep); } + void visit(AstRealToBits* nodep) override { visit_Ou64_Lr(nodep); } // Output integer, input string - virtual void visit(AstLenN* nodep) override { visit_Os32_string(nodep); } - virtual void visit(AstPutcN* nodep) override { + void visit(AstLenN* nodep) override { visit_Os32_string(nodep); } + void visit(AstPutcN* nodep) override { // CALLER: str.putc() UASSERT_OBJ(nodep->rhsp() && nodep->thsp(), nodep, "For ternary ops only!"); if (m_vup && m_vup->prelim()) { @@ -391,7 +386,7 @@ private: // AstAssign } } - virtual void visit(AstGetcN* nodep) override { + void visit(AstGetcN* nodep) override { // CALLER: str.getc() UASSERT_OBJ(nodep->rhsp(), nodep, "For binary ops only!"); if (m_vup && m_vup->prelim()) { @@ -401,7 +396,7 @@ private: nodep->dtypeSetBitSized(8, VSigning::UNSIGNED); } } - virtual void visit(AstGetcRefN* nodep) override { + void visit(AstGetcRefN* nodep) override { // CALLER: str.getc() UASSERT_OBJ(nodep->rhsp(), nodep, "For binary ops only!"); if (m_vup && m_vup->prelim()) { @@ -411,7 +406,7 @@ private: nodep->dtypeSetBitSized(8, VSigning::UNSIGNED); } } - virtual void visit(AstSubstrN* nodep) override { + void visit(AstSubstrN* nodep) override { // CALLER: str.substr() UASSERT_OBJ(nodep->rhsp() && nodep->thsp(), nodep, "For ternary ops only!"); if (m_vup && m_vup->prelim()) { @@ -422,7 +417,7 @@ private: nodep->dtypeSetString(); } } - virtual void visit(AstCompareNN* nodep) override { + void visit(AstCompareNN* nodep) override { // CALLER: str.compare(), str.icompare() // Widths: 32 bit out UASSERT_OBJ(nodep->rhsp(), nodep, "For binary ops only!"); @@ -433,7 +428,7 @@ private: nodep->dtypeSetSigned32(); } } - virtual void visit(AstAtoN* nodep) override { + void visit(AstAtoN* nodep) override { // CALLER: str.atobin(), atoi(), atohex(), atooct(), atoreal() // Width: 64bit floating point for atoreal(), 32bit out for the others if (m_vup->prelim()) { @@ -448,13 +443,13 @@ private: } // Widths: Constant, terminal - virtual void visit(AstTime* nodep) override { nodep->dtypeSetUInt64(); } - virtual void visit(AstTimeD* nodep) override { nodep->dtypeSetDouble(); } - virtual void visit(AstScopeName* nodep) override { + void visit(AstTime* nodep) override { nodep->dtypeSetUInt64(); } + void visit(AstTimeD* nodep) override { nodep->dtypeSetDouble(); } + void visit(AstScopeName* nodep) override { nodep->dtypeSetUInt64(); // A pointer, but not that it matters } - virtual void visit(AstNodeCond* nodep) override { + void visit(AstNodeCond* nodep) override { // op = cond ? expr1 : expr2 // See IEEE-2012 11.4.11 and Table 11-21. // LHS is self-determined @@ -466,22 +461,22 @@ private: iterateCheckBool(nodep, "Conditional Test", nodep->condp(), BOTH); // Determine sub expression widths only relying on what's in the subops // CONTEXT determined, but need data type for pattern assignments - userIterateAndNext(nodep->expr1p(), WidthVP(m_vup->dtypeNullp(), PRELIM).p()); - userIterateAndNext(nodep->expr2p(), WidthVP(m_vup->dtypeNullp(), PRELIM).p()); + userIterateAndNext(nodep->thenp(), WidthVP(m_vup->dtypeNullp(), PRELIM).p()); + userIterateAndNext(nodep->elsep(), WidthVP(m_vup->dtypeNullp(), PRELIM).p()); // Calculate width of this expression. // First call (prelim()) m_vup->width() is probably zero, so we'll return // the size of this subexpression only. // Second call (final()) m_vup->width() is probably the expression size, so // the expression includes the size of the output too. - if (nodep->expr1p()->isDouble() || nodep->expr2p()->isDouble()) { + if (nodep->thenp()->isDouble() || nodep->elsep()->isDouble()) { nodep->dtypeSetDouble(); - } else if (nodep->expr1p()->isString() || nodep->expr2p()->isString()) { + } else if (nodep->thenp()->isString() || nodep->elsep()->isString()) { nodep->dtypeSetString(); } else { - const int width = std::max(nodep->expr1p()->width(), nodep->expr2p()->width()); + const int width = std::max(nodep->thenp()->width(), nodep->elsep()->width()); const int mwidth - = std::max(nodep->expr1p()->widthMin(), nodep->expr2p()->widthMin()); - const bool issigned = nodep->expr1p()->isSigned() && nodep->expr2p()->isSigned(); + = std::max(nodep->thenp()->widthMin(), nodep->elsep()->widthMin()); + const bool issigned = nodep->thenp()->isSigned() && nodep->elsep()->isSigned(); nodep->dtypeSetLogicUnsized(width, mwidth, VSigning::fromBool(issigned)); } } @@ -490,13 +485,13 @@ private: AstNodeDType* const subDTypep = expDTypep; nodep->dtypeFrom(expDTypep); // Error report and change sizes for suboperands of this node. - iterateCheck(nodep, "Conditional True", nodep->expr1p(), CONTEXT, FINAL, subDTypep, + iterateCheck(nodep, "Conditional True", nodep->thenp(), CONTEXT, FINAL, subDTypep, EXTEND_EXP); - iterateCheck(nodep, "Conditional False", nodep->expr2p(), CONTEXT, FINAL, subDTypep, + iterateCheck(nodep, "Conditional False", nodep->elsep(), CONTEXT, FINAL, subDTypep, EXTEND_EXP); } } - virtual void visit(AstConcat* nodep) override { + void visit(AstConcat* nodep) override { // Real: Not allowed (assumed) // Signed: unsigned output, input either (assumed) // IEEE-2012 Table 11-21, and 11.8.1: @@ -538,7 +533,7 @@ private: || VN_IS(vdtypep, DynArrayDType) // || VN_IS(vdtypep, QueueDType)) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: Concatenation to form " - << vdtypep->prettyDTypeNameQ() << "data type"); + << vdtypep->prettyDTypeNameQ() << " data type"); } iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); @@ -579,7 +574,7 @@ private: } } } - virtual void visit(AstConcatN* nodep) override { + void visit(AstConcatN* nodep) override { // String concatenate. // Already did AstConcat simplifications if (m_vup->prelim()) { @@ -595,7 +590,7 @@ private: } } } - virtual void visit(AstDelay* nodep) override { + void visit(AstDelay* nodep) override { if (VN_IS(m_procedurep, Final)) { nodep->v3error("Delays are not legal in final blocks (IEEE 1800-2017 9.2.3)"); VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); @@ -611,7 +606,7 @@ private: nodep->v3warn(STMTDLY, "Unsupported: Ignoring delay on this delayed statement."); VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); } - virtual void visit(AstFork* nodep) override { + void visit(AstFork* nodep) override { if (VN_IS(m_ftaskp, Func) && !nodep->joinType().joinNone()) { nodep->v3error("Only fork .. join_none is legal in functions. " "(IEEE 1800-2017 13.4.4)"); @@ -633,27 +628,27 @@ private: // TBD might support only normal join, if so complain about other join flavors } } - virtual void visit(AstDisableFork* nodep) override { + void visit(AstDisableFork* nodep) override { nodep->v3warn(E_UNSUPPORTED, "Unsupported: disable fork statements"); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } - virtual void visit(AstWaitFork* nodep) override { + void visit(AstWaitFork* nodep) override { nodep->v3warn(E_UNSUPPORTED, "Unsupported: wait fork statements"); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } - virtual void visit(AstToLowerN* nodep) override { + void visit(AstToLowerN* nodep) override { if (m_vup->prelim()) { iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH); nodep->dtypeSetString(); } } - virtual void visit(AstToUpperN* nodep) override { + void visit(AstToUpperN* nodep) override { if (m_vup->prelim()) { iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH); nodep->dtypeSetString(); } } - virtual void visit(AstReplicate* nodep) override { + void visit(AstReplicate* nodep) override { // IEEE-2012 Table 11-21: // LHS, RHS is self-determined // width: value(LHS) * width(RHS) @@ -714,7 +709,7 @@ private: } } } - virtual void visit(AstReplicateN* nodep) override { + void visit(AstReplicateN* nodep) override { // Replicate with string if (m_vup->prelim()) { iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH); @@ -741,7 +736,7 @@ private: } } } - virtual void visit(AstNodeStream* nodep) override { + void visit(AstNodeStream* nodep) override { if (m_vup->prelim()) { iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH); @@ -774,7 +769,7 @@ private: } } } - virtual void visit(AstRange* nodep) override { + void visit(AstRange* nodep) override { // Real: Not allowed // Signed: unsigned output, input either // Convert all range values to constants @@ -800,7 +795,7 @@ private: } } - virtual void visit(AstSel* nodep) override { + void visit(AstSel* nodep) override { // Signed: always unsigned; Real: Not allowed // LSB is self-determined (IEEE 2012 11.5.1) // We also use SELs to shorten a signed constant etc, in this case they are signed. @@ -907,7 +902,7 @@ private: } } - virtual void visit(AstArraySel* nodep) override { + void visit(AstArraySel* nodep) override { // Signed/Real: Output signed iff LHS signed/real; binary operator // Note by contrast, bit extract selects are unsigned // LSB is self-determined (IEEE 2012 11.5.1) @@ -969,7 +964,7 @@ private: } } - virtual void visit(AstAssocSel* nodep) override { + void visit(AstAssocSel* nodep) override { // Signed/Real: Output type based on array-declared type; binary operator if (m_vup->prelim()) { const AstNodeDType* const fromDtp = nodep->fromp()->dtypep()->skipRefp(); @@ -984,7 +979,7 @@ private: } } - virtual void visit(AstWildcardSel* nodep) override { + void visit(AstWildcardSel* nodep) override { // Signed/Real: Output type based on array-declared type; binary operator if (m_vup->prelim()) { const AstNodeDType* const fromDtp = nodep->fromp()->dtypep()->skipRefp(); @@ -1005,7 +1000,7 @@ private: } } - virtual void visit(AstSliceSel* nodep) override { + void visit(AstSliceSel* nodep) override { // Always creates as output an unpacked array if (m_vup->prelim()) { userIterateAndNext(nodep->fromp(), WidthVP(SELF, BOTH).p()); @@ -1049,7 +1044,7 @@ private: } } - virtual void visit(AstSelBit* nodep) override { + void visit(AstSelBit* nodep) override { // Just a quick check as after V3Param these nodes instead are AstSel's userIterateAndNext(nodep->fromp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel userIterateAndNext(nodep->rhsp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel @@ -1063,7 +1058,7 @@ private: } nodep->v3fatalSrc("AstSelBit should disappear after widthSel"); } - virtual void visit(AstSelExtract* nodep) override { + void visit(AstSelExtract* nodep) override { // Just a quick check as after V3Param these nodes instead are AstSel's userIterateAndNext(nodep->fromp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel userIterateAndNext(nodep->rhsp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel @@ -1077,7 +1072,7 @@ private: } nodep->v3fatalSrc("AstSelExtract should disappear after widthSel"); } - virtual void visit(AstSelPlus* nodep) override { + void visit(AstSelPlus* nodep) override { userIterateAndNext(nodep->fromp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel userIterateAndNext(nodep->rhsp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel userIterateAndNext(nodep->thsp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel @@ -1090,7 +1085,7 @@ private: } nodep->v3fatalSrc("AstSelPlus should disappear after widthSel"); } - virtual void visit(AstSelMinus* nodep) override { + void visit(AstSelMinus* nodep) override { userIterateAndNext(nodep->fromp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel userIterateAndNext(nodep->rhsp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel userIterateAndNext(nodep->thsp(), WidthVP(CONTEXT, PRELIM).p()); // FINAL in AstSel @@ -1104,13 +1099,13 @@ private: nodep->v3fatalSrc("AstSelMinus should disappear after widthSel"); } - virtual void visit(AstExtend* nodep) override { + void visit(AstExtend* nodep) override { // Only created by this process, so we know width from here down is correct. } - virtual void visit(AstExtendS* nodep) override { + void visit(AstExtendS* nodep) override { // Only created by this process, so we know width from here down is correct. } - virtual void visit(AstConst* nodep) override { + void visit(AstConst* nodep) override { // The node got setup with the signed/real state of the node. // However a later operation may have changed the node->signed w/o changing // the number's sign. So we don't: nodep->dtypeChgSigned(nodep->num().isSigned()); @@ -1126,20 +1121,20 @@ private: // We don't size the constant until we commit the widths, as need parameters // to remain unsized, and numbers to remain unsized to avoid backp() warnings } - virtual void visit(AstEmptyQueue* nodep) override { + void visit(AstEmptyQueue* nodep) override { nodep->dtypeSetEmptyQueue(); if (!VN_IS(nodep->backp(), Assign)) { nodep->v3warn(E_UNSUPPORTED, "Unsupported/Illegal: empty queue ('{}') in this context"); } } - virtual void visit(AstFell* nodep) override { + void visit(AstFell* nodep) override { if (m_vup->prelim()) { iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH); nodep->dtypeSetBit(); } } - virtual void visit(AstPast* nodep) override { + void visit(AstPast* nodep) override { if (m_vup->prelim()) { iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH); nodep->dtypeFrom(nodep->exprp()); @@ -1163,28 +1158,28 @@ private: } } } - virtual void visit(AstRose* nodep) override { + void visit(AstRose* nodep) override { if (m_vup->prelim()) { iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH); nodep->dtypeSetBit(); } } - virtual void visit(AstSampled* nodep) override { + void visit(AstSampled* nodep) override { if (m_vup->prelim()) { iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH); nodep->dtypeFrom(nodep->exprp()); } } - virtual void visit(AstStable* nodep) override { + void visit(AstStable* nodep) override { if (m_vup->prelim()) { iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH); nodep->dtypeSetBit(); } } - virtual void visit(AstImplication* nodep) override { + void visit(AstImplication* nodep) override { if (m_vup->prelim()) { iterateCheckBool(nodep, "LHS", nodep->lhsp(), BOTH); iterateCheckBool(nodep, "RHS", nodep->rhsp(), BOTH); @@ -1192,7 +1187,7 @@ private: } } - virtual void visit(AstRand* nodep) override { + void visit(AstRand* nodep) override { if (m_vup->prelim()) { if (nodep->urandom()) { nodep->dtypeSetUInt32(); // Says the spec @@ -1202,7 +1197,7 @@ private: if (nodep->seedp()) iterateCheckSigned32(nodep, "seed", nodep->seedp(), BOTH); } } - virtual void visit(AstURandomRange* nodep) override { + void visit(AstURandomRange* nodep) override { if (m_vup->prelim()) { nodep->dtypeSetUInt32(); // Says the spec AstNodeDType* const expDTypep = nodep->findUInt32DType(); @@ -1212,7 +1207,7 @@ private: iterateCheck(nodep, "RHS", nodep->rhsp(), SELF, FINAL, expDTypep, EXTEND_EXP); } } - virtual void visit(AstUnbounded* nodep) override { + void visit(AstUnbounded* nodep) override { nodep->dtypeSetSigned32(); // Used in int context if (VN_IS(nodep->backp(), IsUnbounded)) return; // Ok, leave if (VN_IS(nodep->backp(), BracketArrayDType)) return; // Ok, leave @@ -1230,13 +1225,13 @@ private: } nodep->v3warn(E_UNSUPPORTED, "Unsupported/illegal unbounded ('$') in this context."); } - virtual void visit(AstIsUnbounded* nodep) override { + void visit(AstIsUnbounded* nodep) override { if (m_vup->prelim()) { userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p()); nodep->dtypeSetBit(); } } - virtual void visit(AstUCFunc* nodep) override { + void visit(AstUCFunc* nodep) override { // Give it the size the user wants. if (m_vup && m_vup->prelim()) { nodep->dtypeSetLogicUnsized(32, 1, VSigning::UNSIGNED); // We don't care @@ -1251,10 +1246,10 @@ private: } } } - virtual void visit(AstCLog2* nodep) override { + void visit(AstCLog2* nodep) override { if (m_vup->prelim()) { iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); } } - virtual void visit(AstPow* nodep) override { + void visit(AstPow* nodep) override { // Pow is special, output sign only depends on LHS sign, but // function result depends on both signs // RHS is self-determined (IEEE) @@ -1298,25 +1293,25 @@ private: } } } - virtual void visit(AstPowSU* nodep) override { + void visit(AstPowSU* nodep) override { // POWSU/SS/US only created here, dtype already determined, so // nothing to do in this function userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p()); userIterateAndNext(nodep->rhsp(), WidthVP(SELF, BOTH).p()); } - virtual void visit(AstPowSS* nodep) override { + void visit(AstPowSS* nodep) override { // POWSU/SS/US only created here, dtype already determined, so // nothing to do in this function userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p()); userIterateAndNext(nodep->rhsp(), WidthVP(SELF, BOTH).p()); } - virtual void visit(AstPowUS* nodep) override { + void visit(AstPowUS* nodep) override { // POWSU/SS/US only created here, dtype already determined, so // nothing to do in this function userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p()); userIterateAndNext(nodep->rhsp(), WidthVP(SELF, BOTH).p()); } - virtual void visit(AstCountBits* nodep) override { + void visit(AstCountBits* nodep) override { if (m_vup->prelim()) { iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH); @@ -1328,7 +1323,7 @@ private: VSigning::UNSIGNED); // Spec doesn't indicate if an integer } } - virtual void visit(AstCountOnes* nodep) override { + void visit(AstCountOnes* nodep) override { if (m_vup->prelim()) { iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); // If it's a 32 bit number, we need a 6 bit number as we need to return '32'. @@ -1337,12 +1332,12 @@ private: VSigning::UNSIGNED); // Spec doesn't indicate if an integer } } - virtual void visit(AstCvtPackString* nodep) override { + void visit(AstCvtPackString* nodep) override { // Opaque returns, so arbitrary userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p()); // Type set in constructor } - virtual void visit(AstTimeImport* nodep) override { + void visit(AstTimeImport* nodep) override { // LHS is a real number in seconds // Need to round to time units and precision userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p()); @@ -1357,14 +1352,14 @@ private: nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } - virtual void visit(AstEventControl* nodep) override { + void visit(AstEventControl* nodep) override { nodep->v3warn(E_UNSUPPORTED, "Unsupported: event control statement in this location\n" << nodep->warnMore() << "... Suggest have one event control statement " << "per procedure, at the top of the procedure"); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } - virtual void visit(AstAttrOf* nodep) override { + void visit(AstAttrOf* nodep) override { VL_RESTORER(m_attrp); m_attrp = nodep; userIterateAndNext(nodep->fromp(), WidthVP(SELF, BOTH).p()); @@ -1497,16 +1492,16 @@ private: } } } - virtual void visit(AstPull* nodep) override { + void visit(AstPull* nodep) override { // May have select underneath, let seek natural size userIterateChildren(nodep, WidthVP(SELF, BOTH).p()); } - virtual void visit(AstText* nodep) override { + void visit(AstText* nodep) override { // Only used in CStmts which don't care.... } // DTYPES - virtual void visit(AstNodeArrayDType* nodep) override { + void visit(AstNodeArrayDType* nodep) override { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed if (nodep->subDTypep() == nodep->basicp()) { // Innermost dimension @@ -1537,7 +1532,7 @@ private: } UINFO(4, "dtWidthed " << nodep << endl); } - virtual void visit(AstAssocArrayDType* nodep) override { + void visit(AstAssocArrayDType* nodep) override { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed // Iterate into subDTypep() to resolve that type and update pointer. nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); @@ -1545,7 +1540,7 @@ private: nodep->dtypep(nodep); // The array itself, not subDtype UINFO(4, "dtWidthed " << nodep << endl); } - virtual void visit(AstBracketArrayDType* nodep) override { + void visit(AstBracketArrayDType* nodep) override { // Type inserted only because parser didn't know elementsp() type // Resolve elementsp's type userIterateChildren(nodep, WidthVP(SELF, BOTH).p()); @@ -1574,14 +1569,14 @@ private: // visit VL_DO_DANGLING(userIterate(newp, nullptr), newp); } - virtual void visit(AstDynArrayDType* nodep) override { + void visit(AstDynArrayDType* nodep) override { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed // Iterate into subDTypep() to resolve that type and update pointer. nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); nodep->dtypep(nodep); // The array itself, not subDtype UINFO(4, "dtWidthed " << nodep << endl); } - virtual void visit(AstQueueDType* nodep) override { + void visit(AstQueueDType* nodep) override { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed // Iterate into subDTypep() to resolve that type and update pointer. nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); @@ -1591,12 +1586,12 @@ private: } UINFO(4, "dtWidthed " << nodep << endl); } - virtual void visit(AstVoidDType* nodep) override { + void visit(AstVoidDType* nodep) override { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed nodep->dtypep(nodep); UINFO(4, "dtWidthed " << nodep << endl); } - virtual void visit(AstUnsizedArrayDType* nodep) override { + void visit(AstUnsizedArrayDType* nodep) override { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed // Iterate into subDTypep() to resolve that type and update pointer. nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); @@ -1604,7 +1599,7 @@ private: nodep->dtypep(nodep); // The array itself, not subDtype UINFO(4, "dtWidthed " << nodep << endl); } - virtual void visit(AstWildcardArrayDType* nodep) override { + void visit(AstWildcardArrayDType* nodep) override { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed // Iterate into subDTypep() to resolve that type and update pointer. nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); @@ -1612,7 +1607,7 @@ private: nodep->dtypep(nodep); // The array itself, not subDtype UINFO(4, "dtWidthed " << nodep << endl); } - virtual void visit(AstBasicDType* nodep) override { + void visit(AstBasicDType* nodep) override { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed if (nodep->generic()) return; // Already perfect if (nodep->rangep()) { @@ -1635,7 +1630,7 @@ private: // dtype Instead for now doing this in V3WidthCommit UINFO(4, "dtWidthed " << nodep << endl); } - virtual void visit(AstConstDType* nodep) override { + void visit(AstConstDType* nodep) override { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed // Iterate into subDTypep() to resolve that type and update pointer. nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); @@ -1644,7 +1639,7 @@ private: nodep->widthFromSub(nodep->subDTypep()); UINFO(4, "dtWidthed " << nodep << endl); } - virtual void visit(AstRefDType* nodep) override { + void visit(AstRefDType* nodep) override { if (nodep->doingWidth()) { // Early exit if have circular parameter definition nodep->v3error("Typedef's type is circular: " << nodep->prettyName()); nodep->dtypeSetBit(); @@ -1682,7 +1677,7 @@ private: UINFO(4, "dtWidthed " << nodep << endl); nodep->doingWidth(false); } - virtual void visit(AstTypedef* nodep) override { + void visit(AstTypedef* nodep) override { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed if (auto* const refp = checkRefToTypedefRecurse(nodep, nodep)) { nodep->v3error("Typedef has self-reference: " << nodep->prettyNameQ() << '\n' @@ -1698,13 +1693,13 @@ private: nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); userIterateChildren(nodep, nullptr); } - virtual void visit(AstParamTypeDType* nodep) override { + void visit(AstParamTypeDType* nodep) override { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); userIterateChildren(nodep, nullptr); nodep->widthFromSub(nodep->subDTypep()); } - virtual void visit(AstCastDynamic* nodep) override { + void visit(AstCastDynamic* nodep) override { nodep->dtypeChgWidthSigned(32, 1, VSigning::SIGNED); // Spec says integer return userIterateChildren(nodep, WidthVP(SELF, BOTH).p()); AstNodeDType* const toDtp = nodep->top()->dtypep()->skipRefToEnump(); @@ -1779,7 +1774,7 @@ private: VL_DO_DANGLING(pushDeletep(nodep), nodep); userIterate(newp, m_vup); } - virtual void visit(AstCastParse* nodep) override { + void visit(AstCastParse* nodep) override { // nodep->dtp could be data type, or a primary_constant // Don't iterate lhsp, will deal with that once convert the type V3Const::constifyParamsEdit(nodep->dtp()); // itemp may change @@ -1796,7 +1791,7 @@ private: nodep->replaceWith(nodep->lhsp()->unlinkFrBack()); } } - virtual void visit(AstCast* nodep) override { + void visit(AstCast* nodep) override { nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); if (m_vup->prelim()) { // if (debug()) nodep->dumpTree(cout, " CastPre: "); @@ -1838,7 +1833,7 @@ private: castSized(nodep, nodep->fromp(), width); // Note castSized might modify nodep->fromp() } else { - iterateCheck(nodep, "value", nodep->lhsp(), SELF, FINAL, fromDtp, EXTEND_EXP, + iterateCheck(nodep, "value", nodep->fromp(), SELF, FINAL, fromDtp, EXTEND_EXP, false); } if (basicp->isDouble() && !nodep->fromp()->isDouble()) { @@ -1870,20 +1865,20 @@ private: << toDtp->prettyDTypeNameQ()); } if (!newp) newp = nodep->fromp()->unlinkFrBack(); - nodep->lhsp(newp); + nodep->fromp(newp); // if (debug()) nodep->dumpTree(cout, " CastOut: "); // if (debug()) nodep->backp()->dumpTree(cout, " CastOutUpUp: "); } if (m_vup->final()) { - iterateCheck(nodep, "value", nodep->lhsp(), SELF, FINAL, nodep->lhsp()->dtypep(), + iterateCheck(nodep, "value", nodep->fromp(), SELF, FINAL, nodep->fromp()->dtypep(), EXTEND_EXP, false); - AstNode* const underp = nodep->lhsp()->unlinkFrBack(); + AstNode* const underp = nodep->fromp()->unlinkFrBack(); // if (debug()) underp->dumpTree(cout, " CastRep: "); nodep->replaceWith(underp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } } - virtual void visit(AstCastSize* nodep) override { + void visit(AstCastSize* nodep) override { // IEEE: Signedness of result is same as self-determined signedness // However, the result is same as BITSEL, so we do not sign extend the LHS UASSERT_OBJ(VN_IS(nodep->rhsp(), Const), nodep, "Unsupported: Non-const cast of size"); @@ -1943,7 +1938,7 @@ private: VL_DANGLING(underp); } } - virtual void visit(AstVar* nodep) override { + void visit(AstVar* nodep) override { // if (debug()) nodep->dumpTree(cout, " InitPre: "); // Must have deterministic constant width // We can't skip this step when width()!=0, as creating a AstVar @@ -2055,7 +2050,7 @@ private: nodep->didWidth(true); nodep->doingWidth(false); } - virtual void visit(AstNodeVarRef* nodep) override { + void visit(AstNodeVarRef* nodep) override { if (nodep->didWidth()) return; if (!nodep->varp()) { if (m_paramsOnly && VN_IS(nodep, VarXRef)) { @@ -2092,7 +2087,7 @@ private: nodep->didWidth(true); } - virtual void visit(AstEnumDType* nodep) override { + void visit(AstEnumDType* nodep) override { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed UINFO(5, " ENUMDTYPE " << nodep << endl); nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); @@ -2156,7 +2151,7 @@ private: num.opAdd(one, constp->num()); } } - virtual void visit(AstEnumItem* nodep) override { + void visit(AstEnumItem* nodep) override { UINFO(5, " ENUMITEM " << nodep << endl); AstNodeDType* const vdtypep = m_vup->dtypep(); UASSERT_OBJ(vdtypep, nodep, "ENUMITEM not under ENUM"); @@ -2170,7 +2165,7 @@ private: EXTEND_EXP); } } - virtual void visit(AstEnumItemRef* nodep) override { + void visit(AstEnumItemRef* nodep) override { if (!nodep->itemp()->didWidth()) { // We need to do the whole enum en-mass AstNode* enump = nodep->itemp(); @@ -2183,7 +2178,7 @@ private: } nodep->dtypeFrom(nodep->itemp()); } - virtual void visit(AstConsAssoc* nodep) override { + void visit(AstConsAssoc* nodep) override { // Type computed when constructed here auto* const vdtypep = VN_AS(m_vup->dtypep()->skipRefp(), AssocArrayDType); UASSERT_OBJ(vdtypep, nodep, "ConsAssoc requires assoc upper parent data type"); @@ -2195,7 +2190,7 @@ private: } } } - virtual void visit(AstSetAssoc* nodep) override { + void visit(AstSetAssoc* nodep) override { // Type computed when constructed here auto* const vdtypep = VN_AS(m_vup->dtypep()->skipRefp(), AssocArrayDType); UASSERT_OBJ(vdtypep, nodep, "SetsAssoc requires assoc upper parent data type"); @@ -2208,7 +2203,7 @@ private: EXTEND_EXP); } } - virtual void visit(AstConsWildcard* nodep) override { + void visit(AstConsWildcard* nodep) override { // Type computed when constructed here auto* const vdtypep = VN_AS(m_vup->dtypep()->skipRefp(), WildcardArrayDType); UASSERT_OBJ(vdtypep, nodep, "ConsWildcard requires wildcard upper parent data type"); @@ -2220,7 +2215,7 @@ private: } } } - virtual void visit(AstSetWildcard* nodep) override { + void visit(AstSetWildcard* nodep) override { // Type computed when constructed here auto* const vdtypep = VN_AS(m_vup->dtypep()->skipRefp(), WildcardArrayDType); UASSERT_OBJ(vdtypep, nodep, "SetWildcard requires wildcard upper parent data type"); @@ -2233,7 +2228,7 @@ private: EXTEND_EXP); } } - virtual void visit(AstConsDynArray* nodep) override { + void visit(AstConsDynArray* nodep) override { // Type computed when constructed here AstDynArrayDType* const vdtypep = VN_AS(m_vup->dtypep()->skipRefp(), DynArrayDType); UASSERT_OBJ(vdtypep, nodep, "ConsDynArray requires queue upper parent data type"); @@ -2265,7 +2260,7 @@ private: nodep->dtypeFrom(vdtypep); } } - virtual void visit(AstConsQueue* nodep) override { + void visit(AstConsQueue* nodep) override { // Type computed when constructed here AstQueueDType* const vdtypep = VN_AS(m_vup->dtypep()->skipRefp(), QueueDType); UASSERT_OBJ(vdtypep, nodep, "ConsQueue requires queue upper parent data type"); @@ -2297,10 +2292,10 @@ private: nodep->dtypeFrom(vdtypep); } } - virtual void visit(AstInitItem* nodep) override { // + void visit(AstInitItem* nodep) override { // userIterateChildren(nodep, m_vup); } - virtual void visit(AstInitArray* nodep) override { + void visit(AstInitArray* nodep) override { // InitArray has type of the array; children are array values if (m_vup->prelim()) { // First stage evaluation AstNodeDType* const vdtypep = m_vup->dtypeNullp(); @@ -2315,7 +2310,7 @@ private: } } } - virtual void visit(AstInside* nodep) override { + void visit(AstInside* nodep) override { userIterateAndNext(nodep->exprp(), WidthVP(CONTEXT, PRELIM).p()); for (AstNode *nextip, *itemp = nodep->itemsp(); itemp; itemp = nextip) { nextip = itemp->nextp(); // Prelim may cause the node to get replaced @@ -2374,14 +2369,14 @@ private: nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } - virtual void visit(AstInsideRange* nodep) override { + void visit(AstInsideRange* nodep) override { // Just do each side; AstInside will rip these nodes out later userIterateAndNext(nodep->lhsp(), m_vup); userIterateAndNext(nodep->rhsp(), m_vup); nodep->dtypeFrom(nodep->lhsp()); } - virtual void visit(AstIfaceRefDType* nodep) override { + void visit(AstIfaceRefDType* nodep) override { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed UINFO(5, " IFACEREF " << nodep << endl); userIterateChildren(nodep, m_vup); @@ -2389,7 +2384,7 @@ private: nodep->widthForce(1, 1); // Not really relevant UINFO(4, "dtWidthed " << nodep << endl); } - virtual void visit(AstNodeUOrStructDType* nodep) override { + void visit(AstNodeUOrStructDType* nodep) override { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed UINFO(5, " NODECLASS " << nodep << endl); // if (debug() >= 9) nodep->dumpTree("-class-in--"); @@ -2424,7 +2419,7 @@ private: nodep->widthForce(width, width); // Signing stays as-is, as parsed from declaration // if (debug() >= 9) nodep->dumpTree("-class-out-"); } - virtual void visit(AstClass* nodep) override { + void visit(AstClass* nodep) override { if (nodep->didWidthAndSet()) return; // Must do extends first, as we may in functions under this class // start following a tree of extends that takes us to other classes @@ -2432,37 +2427,37 @@ private: userIterateChildren(nodep, nullptr); // First size all members nodep->repairCache(); } - virtual void visit(AstClassRefDType* nodep) override { + void visit(AstClassRefDType* nodep) override { if (nodep->didWidthAndSet()) return; // TODO this maybe eventually required to properly resolve members, // though causes problems with t_class_forward.v, so for now avoided // userIterateChildren(nodep->classp(), nullptr); } - virtual void visit(AstClassOrPackageRef* nodep) override { + void visit(AstClassOrPackageRef* nodep) override { if (nodep->didWidthAndSet()) return; userIterateChildren(nodep, nullptr); } - virtual void visit(AstDot* nodep) override { + void visit(AstDot* nodep) override { // We can only reach this from constify called during V3Param (so before linkDotParam) // ... #(Cls#(...)::...) ... // ^^~~~ this is our DOT nodep->v3warn(E_UNSUPPORTED, "dotted expressions in parameters\n" << nodep->warnMore() << "... Suggest use a typedef"); } - virtual void visit(AstClassExtends* nodep) override { + void visit(AstClassExtends* nodep) override { if (nodep->didWidthAndSet()) return; if (VN_IS(nodep->childDTypep(), ClassRefDType)) { nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->childDTypep())); } } - virtual void visit(AstMemberDType* nodep) override { + void visit(AstMemberDType* nodep) override { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed // Iterate into subDTypep() to resolve that type and update pointer. nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); nodep->dtypep(nodep); // The member itself, not subDtype nodep->widthFromSub(nodep->subDTypep()); } - virtual void visit(AstMemberSel* nodep) override { + void visit(AstMemberSel* nodep) override { UINFO(5, " MEMBERSEL " << nodep << endl); if (debug() >= 9) nodep->dumpTree("-mbs-in: "); userIterateChildren(nodep, WidthVP(SELF, BOTH).p()); @@ -2565,12 +2560,12 @@ private: return false; } - virtual void visit(AstCMethodHard* nodep) override { + void visit(AstCMethodHard* nodep) override { // Never created before V3Width, so no need to redo it UASSERT_OBJ(nodep->dtypep(), nodep, "CMETHODCALLs should have already been sized"); } - virtual void visit(AstMethodCall* nodep) override { + void visit(AstMethodCall* nodep) override { UINFO(5, " METHODCALL " << nodep << endl); if (nodep->didWidth()) return; if (debug() >= 9) nodep->dumpTree("-mts-in: "); @@ -3218,6 +3213,7 @@ private: nodep->dtypeFrom(ftaskp); nodep->classOrPackagep(classp); if (VN_IS(ftaskp, Task)) nodep->makeStatement(); + processFTaskRefArgs(nodep); } return; } @@ -3417,7 +3413,7 @@ private: } } - virtual void visit(AstNew* nodep) override { + void visit(AstNew* nodep) override { if (nodep->didWidth()) return; AstClassRefDType* const refp = m_vup ? VN_CAST(m_vup->dtypeNullSkipRefp(), ClassRefDType) : nullptr; @@ -3443,7 +3439,7 @@ private: userIterate(nodep->taskp(), nullptr); processFTaskRefArgs(nodep); } - virtual void visit(AstNewCopy* nodep) override { + void visit(AstNewCopy* nodep) override { if (nodep->didWidthAndSet()) return; AstClassRefDType* const refp = VN_CAST(m_vup->dtypeNullSkipRefp(), ClassRefDType); if (!refp) { // e.g. int a = new; @@ -3458,7 +3454,7 @@ private: << nodep->rhsp()->dtypep()->prettyTypeName() << "'"); } } - virtual void visit(AstNewDynamic* nodep) override { + void visit(AstNewDynamic* nodep) override { if (nodep->didWidthAndSet()) return; AstDynArrayDType* const adtypep = VN_CAST(m_vup->dtypeNullSkipRefp(), DynArrayDType); if (!adtypep) { // e.g. int a = new; @@ -3482,7 +3478,7 @@ private: } } - virtual void visit(AstPattern* nodep) override { + void visit(AstPattern* nodep) override { if (nodep->didWidthAndSet()) return; UINFO(9, "PATTERN " << nodep << endl); if (nodep->childDTypep()) { // data_type '{ pattern } @@ -3918,7 +3914,7 @@ private: return valuep; } - virtual void visit(AstPatMember* nodep) override { + void visit(AstPatMember* nodep) override { AstNodeDType* const vdtypep = m_vup->dtypeNullp(); UASSERT_OBJ(vdtypep, nodep, "Pattern member type not assigned by AstPattern visitor"); nodep->dtypep(vdtypep); @@ -3952,7 +3948,7 @@ private: return times; } - virtual void visit(AstPropClocked* nodep) override { + void visit(AstPropClocked* nodep) override { if (m_vup->prelim()) { // First stage evaluation iterateCheckBool(nodep, "Property", nodep->propp(), BOTH); userIterateAndNext(nodep->sensesp(), nullptr); @@ -3967,7 +3963,7 @@ private: //-------------------- // Top levels - virtual void visit(AstNodeCase* nodep) override { + void visit(AstNodeCase* nodep) override { // IEEE-2012 12.5: // Width: MAX(expr, all items) // Signed: Only if expr, and all items signed @@ -3975,7 +3971,7 @@ private: userIterateAndNext(nodep->exprp(), WidthVP(CONTEXT, PRELIM).p()); for (AstCaseItem *nextip, *itemp = nodep->itemsp(); itemp; itemp = nextip) { nextip = VN_AS(itemp->nextp(), CaseItem); // Prelim may cause the node to get replaced - if (!VN_IS(nodep, GenCase)) userIterateAndNext(itemp->bodysp(), nullptr); + if (!VN_IS(nodep, GenCase)) userIterateAndNext(itemp->stmtsp(), nullptr); for (AstNode *nextcp, *condp = itemp->condsp(); condp; condp = nextcp) { nextcp = condp->nextp(); // Prelim may cause the node to get replaced VL_DO_DANGLING(userIterate(condp, WidthVP(CONTEXT, PRELIM).p()), condp); @@ -4013,44 +4009,44 @@ private: } } } - virtual void visit(AstNodeFor* nodep) override { + void visit(AstNodeFor* nodep) override { assertAtStatement(nodep); userIterateAndNext(nodep->initsp(), nullptr); iterateCheckBool(nodep, "For Test Condition", nodep->condp(), BOTH); // it's like an if() condition. - if (!VN_IS(nodep, GenFor)) userIterateAndNext(nodep->bodysp(), nullptr); + if (!VN_IS(nodep, GenFor)) userIterateAndNext(nodep->stmtsp(), nullptr); userIterateAndNext(nodep->incsp(), nullptr); } - virtual void visit(AstRepeat* nodep) override { + void visit(AstRepeat* nodep) override { assertAtStatement(nodep); userIterateAndNext(nodep->countp(), WidthVP(SELF, BOTH).p()); - userIterateAndNext(nodep->bodysp(), nullptr); + userIterateAndNext(nodep->stmtsp(), nullptr); } - virtual void visit(AstWhile* nodep) override { + void visit(AstWhile* nodep) override { assertAtStatement(nodep); userIterateAndNext(nodep->precondsp(), nullptr); iterateCheckBool(nodep, "For Test Condition", nodep->condp(), BOTH); // it's like an if() condition. - userIterateAndNext(nodep->bodysp(), nullptr); + userIterateAndNext(nodep->stmtsp(), nullptr); userIterateAndNext(nodep->incsp(), nullptr); } - virtual void visit(AstNodeIf* nodep) override { + void visit(AstNodeIf* nodep) override { assertAtStatement(nodep); // if (debug()) nodep->dumpTree(cout, " IfPre: "); if (!VN_IS(nodep, GenIf)) { // for m_paramsOnly - userIterateAndNext(nodep->ifsp(), nullptr); + userIterateAndNext(nodep->thensp(), nullptr); userIterateAndNext(nodep->elsesp(), nullptr); } iterateCheckBool(nodep, "If", nodep->condp(), BOTH); // it's like an if() condition. // if (debug()) nodep->dumpTree(cout, " IfOut: "); } - virtual void visit(AstExprStmt* nodep) override { + void visit(AstExprStmt* nodep) override { userIterateAndNext(nodep->stmtsp(), nullptr); // expected result is same as parent's expected result userIterateAndNext(nodep->resultp(), m_vup); nodep->dtypeFrom(nodep->resultp()); } - virtual void visit(AstForeach* nodep) override { + void visit(AstForeach* nodep) override { const AstSelLoopVars* const loopsp = VN_CAST(nodep->arrayp(), SelLoopVars); UASSERT_OBJ(loopsp, nodep, "No loop variables under foreach"); // if (debug()) nodep->dumpTree(cout, "-foreach-old: "); @@ -4059,7 +4055,7 @@ private: UASSERT_OBJ(fromp->dtypep(), fromp, "Missing data type"); AstNodeDType* fromDtp = fromp->dtypep()->skipRefp(); // Split into for loop - AstNode* bodyp = nodep->bodysp(); // Might be null + AstNode* bodyp = nodep->stmtsp(); // Might be null if (bodyp) bodyp->unlinkFrBackWithNext(); // We record where the body needs to eventually go with bodyPointp // (Can't use bodyp as might be null) @@ -4213,7 +4209,7 @@ private: return newp; } - virtual void visit(AstNodeAssign* nodep) override { + void visit(AstNodeAssign* nodep) override { // IEEE-2012 10.7, 11.8.2, 11.8.3, 11.5: (Careful of 11.8.1 which is // only one step; final dtype depends on assign LHS.) // Determine RHS type width and signing @@ -4287,13 +4283,13 @@ private: } } - virtual void visit(AstRelease* nodep) override { + void visit(AstRelease* nodep) override { userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p()); UASSERT_OBJ(nodep->lhsp()->dtypep(), nodep, "How can LValue be untyped?"); UASSERT_OBJ(nodep->lhsp()->dtypep()->widthSized(), nodep, "How can LValue be unsized?"); } - virtual void visit(AstSFormatF* nodep) override { + void visit(AstSFormatF* nodep) override { // Excludes NodeDisplay, see below if (m_vup && !m_vup->prelim()) return; // Can be called as statement or function // Just let all arguments seek their natural sizes @@ -4351,8 +4347,8 @@ private: argp->unlinkFrBack(&handle); AstCMath* const newp = new AstCMath(nodep->fileline(), "VL_TO_STRING(", 0, true); - newp->addBodysp(argp); - newp->addBodysp(new AstText(nodep->fileline(), ")", true)); + newp->addExprsp(argp); + newp->addExprsp(new AstText(nodep->fileline(), ")", true)); newp->dtypeSetString(); newp->pure(true); newp->protect(false); @@ -4426,13 +4422,13 @@ private: nodep->text(newFormat); UINFO(9, " Display out " << nodep->text() << endl); } - virtual void visit(AstDisplay* nodep) override { + void visit(AstDisplay* nodep) override { assertAtStatement(nodep); if (nodep->filep()) iterateCheckFileDesc(nodep, nodep->filep(), BOTH); // Just let all arguments seek their natural sizes userIterateChildren(nodep, WidthVP(SELF, BOTH).p()); } - virtual void visit(AstElabDisplay* nodep) override { + void visit(AstElabDisplay* nodep) override { assertAtStatement(nodep); // Just let all arguments seek their natural sizes userIterateChildren(nodep, WidthVP(SELF, BOTH).p()); @@ -4450,28 +4446,28 @@ private: VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } } - virtual void visit(AstDumpCtl* nodep) override { + void visit(AstDumpCtl* nodep) override { assertAtStatement(nodep); // Just let all arguments seek their natural sizes userIterateChildren(nodep, WidthVP(SELF, BOTH).p()); } - virtual void visit(AstFOpen* nodep) override { + void visit(AstFOpen* nodep) override { // Although a system function in IEEE, here a statement which sets the file pointer (MCD) assertAtStatement(nodep); iterateCheckFileDesc(nodep, nodep->filep(), BOTH); userIterateAndNext(nodep->filenamep(), WidthVP(SELF, BOTH).p()); userIterateAndNext(nodep->modep(), WidthVP(SELF, BOTH).p()); } - virtual void visit(AstFOpenMcd* nodep) override { + void visit(AstFOpenMcd* nodep) override { assertAtStatement(nodep); iterateCheckFileDesc(nodep, nodep->filep(), BOTH); userIterateAndNext(nodep->filenamep(), WidthVP(SELF, BOTH).p()); } - virtual void visit(AstFClose* nodep) override { + void visit(AstFClose* nodep) override { assertAtStatement(nodep); iterateCheckFileDesc(nodep, nodep->filep(), BOTH); } - virtual void visit(AstFError* nodep) override { + void visit(AstFError* nodep) override { if (m_vup->prelim()) { iterateCheckFileDesc(nodep, nodep->filep(), BOTH); // We only support string types, not packed array @@ -4479,51 +4475,51 @@ private: nodep->dtypeSetLogicUnsized(32, 1, VSigning::SIGNED); // Spec says integer return } } - virtual void visit(AstFEof* nodep) override { + void visit(AstFEof* nodep) override { if (m_vup->prelim()) { iterateCheckFileDesc(nodep, nodep->filep(), BOTH); nodep->dtypeSetLogicUnsized(32, 1, VSigning::SIGNED); // Spec says integer return } } - virtual void visit(AstFFlush* nodep) override { + void visit(AstFFlush* nodep) override { assertAtStatement(nodep); if (nodep->filep()) iterateCheckFileDesc(nodep, nodep->filep(), BOTH); } - virtual void visit(AstFRewind* nodep) override { + void visit(AstFRewind* nodep) override { iterateCheckFileDesc(nodep, nodep->filep(), BOTH); nodep->dtypeSetLogicUnsized(32, 1, VSigning::SIGNED); // Spec says integer return } - virtual void visit(AstFTell* nodep) override { + void visit(AstFTell* nodep) override { iterateCheckFileDesc(nodep, nodep->filep(), BOTH); nodep->dtypeSetLogicUnsized(32, 1, VSigning::SIGNED); // Spec says integer return } - virtual void visit(AstFSeek* nodep) override { + void visit(AstFSeek* nodep) override { iterateCheckFileDesc(nodep, nodep->filep(), BOTH); iterateCheckSigned32(nodep, "$fseek offset", nodep->offset(), BOTH); iterateCheckSigned32(nodep, "$fseek operation", nodep->operation(), BOTH); nodep->dtypeSetLogicUnsized(32, 1, VSigning::SIGNED); // Spec says integer return } - virtual void visit(AstFGetC* nodep) override { + void visit(AstFGetC* nodep) override { if (m_vup->prelim()) { iterateCheckFileDesc(nodep, nodep->filep(), BOTH); nodep->dtypeSetLogicUnsized(32, 8, VSigning::SIGNED); // Spec says integer return } } - virtual void visit(AstFGetS* nodep) override { + void visit(AstFGetS* nodep) override { if (m_vup->prelim()) { nodep->dtypeSetSigned32(); // Spec says integer return iterateCheckFileDesc(nodep, nodep->filep(), BOTH); userIterateAndNext(nodep->strgp(), WidthVP(SELF, BOTH).p()); } } - virtual void visit(AstFUngetC* nodep) override { + void visit(AstFUngetC* nodep) override { if (m_vup->prelim()) { iterateCheckFileDesc(nodep, nodep->filep(), BOTH); iterateCheckSigned32(nodep, "$fungetc character", nodep->charp(), BOTH); nodep->dtypeSetLogicUnsized(32, 8, VSigning::SIGNED); // Spec says integer return } } - virtual void visit(AstFRead* nodep) override { + void visit(AstFRead* nodep) override { if (m_vup->prelim()) { nodep->dtypeSetSigned32(); // Spec says integer return userIterateAndNext(nodep->memp(), WidthVP(SELF, BOTH).p()); @@ -4536,38 +4532,38 @@ private: } } } - virtual void visit(AstFScanF* nodep) override { + void visit(AstFScanF* nodep) override { if (m_vup->prelim()) { nodep->dtypeSetSigned32(); // Spec says integer return iterateCheckFileDesc(nodep, nodep->filep(), BOTH); userIterateAndNext(nodep->exprsp(), WidthVP(SELF, BOTH).p()); } } - virtual void visit(AstSScanF* nodep) override { + void visit(AstSScanF* nodep) override { if (m_vup->prelim()) { nodep->dtypeSetSigned32(); // Spec says integer return userIterateAndNext(nodep->fromp(), WidthVP(SELF, BOTH).p()); userIterateAndNext(nodep->exprsp(), WidthVP(SELF, BOTH).p()); } } - virtual void visit(AstSysIgnore* nodep) override { + void visit(AstSysIgnore* nodep) override { userIterateAndNext(nodep->exprsp(), WidthVP(SELF, BOTH).p()); } - virtual void visit(AstSystemF* nodep) override { + void visit(AstSystemF* nodep) override { if (m_vup->prelim()) { userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p()); nodep->dtypeSetSigned32(); // Spec says integer return } } - virtual void visit(AstSysFuncAsTask* nodep) override { + void visit(AstSysFuncAsTask* nodep) override { assertAtStatement(nodep); userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p()); } - virtual void visit(AstSystemT* nodep) override { + void visit(AstSystemT* nodep) override { assertAtStatement(nodep); userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p()); } - virtual void visit(AstNodeReadWriteMem* nodep) override { + void visit(AstNodeReadWriteMem* nodep) override { assertAtStatement(nodep); userIterateAndNext(nodep->filenamep(), WidthVP(SELF, BOTH).p()); userIterateAndNext(nodep->memp(), WidthVP(SELF, BOTH).p()); @@ -4599,53 +4595,53 @@ private: userIterateAndNext(nodep->lsbp(), WidthVP(SELF, BOTH).p()); userIterateAndNext(nodep->msbp(), WidthVP(SELF, BOTH).p()); } - virtual void visit(AstTestPlusArgs* nodep) override { + void visit(AstTestPlusArgs* nodep) override { if (m_vup->prelim()) { userIterateAndNext(nodep->searchp(), WidthVP{SELF, BOTH}.p()); nodep->dtypeChgWidthSigned(32, 1, VSigning::SIGNED); // Spec says integer return } } - virtual void visit(AstValuePlusArgs* nodep) override { + void visit(AstValuePlusArgs* nodep) override { if (m_vup->prelim()) { userIterateAndNext(nodep->searchp(), WidthVP(SELF, BOTH).p()); userIterateAndNext(nodep->outp(), WidthVP(SELF, BOTH).p()); nodep->dtypeChgWidthSigned(32, 1, VSigning::SIGNED); // Spec says integer return } } - virtual void visit(AstTimeFormat* nodep) override { + void visit(AstTimeFormat* nodep) override { assertAtStatement(nodep); iterateCheckSigned32(nodep, "units", nodep->unitsp(), BOTH); iterateCheckSigned32(nodep, "precision", nodep->precisionp(), BOTH); iterateCheckString(nodep, "suffix", nodep->suffixp(), BOTH); iterateCheckSigned32(nodep, "width", nodep->widthp(), BOTH); } - virtual void visit(AstUCStmt* nodep) override { + void visit(AstUCStmt* nodep) override { // Just let all arguments seek their natural sizes assertAtStatement(nodep); userIterateChildren(nodep, WidthVP(SELF, BOTH).p()); } - virtual void visit(AstAssert* nodep) override { + void visit(AstAssert* nodep) override { assertAtStatement(nodep); iterateCheckBool(nodep, "Property", nodep->propp(), BOTH); // it's like an if() condition. userIterateAndNext(nodep->passsp(), nullptr); userIterateAndNext(nodep->failsp(), nullptr); } - virtual void visit(AstAssertIntrinsic* nodep) override { + void visit(AstAssertIntrinsic* nodep) override { assertAtStatement(nodep); iterateCheckBool(nodep, "Property", nodep->propp(), BOTH); // it's like an if() condition. userIterateAndNext(nodep->passsp(), nullptr); userIterateAndNext(nodep->failsp(), nullptr); } - virtual void visit(AstCover* nodep) override { + void visit(AstCover* nodep) override { assertAtStatement(nodep); iterateCheckBool(nodep, "Property", nodep->propp(), BOTH); // it's like an if() condition. userIterateAndNext(nodep->passsp(), nullptr); } - virtual void visit(AstRestrict* nodep) override { + void visit(AstRestrict* nodep) override { assertAtStatement(nodep); iterateCheckBool(nodep, "Property", nodep->propp(), BOTH); // it's like an if() condition. } - virtual void visit(AstPin* nodep) override { + void visit(AstPin* nodep) override { // if (debug()) nodep->dumpTree(cout, "- PinPre: "); // TOP LEVEL NODE if (nodep->modVarp() && nodep->modVarp()->isGParam()) { @@ -4770,7 +4766,7 @@ private: } // if (debug()) nodep->dumpTree(cout, "- PinOut: "); } - virtual void visit(AstCell* nodep) override { + void visit(AstCell* nodep) override { VL_RESTORER(m_cellp); m_cellp = nodep; if (!m_paramsOnly) { @@ -4787,7 +4783,7 @@ private: } userIterateAndNext(nodep->paramsp(), nullptr); } - virtual void visit(AstGatePin* nodep) override { + void visit(AstGatePin* nodep) override { if (m_vup->prelim()) { userIterateAndNext(nodep->rangep(), WidthVP(SELF, BOTH).p()); userIterateAndNext(nodep->exprp(), WidthVP(CONTEXT, PRELIM).p()); @@ -4811,7 +4807,7 @@ private: VL_DO_DANGLING(pushDeletep(nodep), nodep); } } - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstNodeFTask* nodep) override { // Grab width from the output variable (if it's a function) if (nodep->didWidth()) return; if (nodep->doingWidth()) { @@ -4853,7 +4849,7 @@ private: // func } } - virtual void visit(AstReturn* nodep) override { + void visit(AstReturn* nodep) override { // IEEE: Assignment-like context assertAtStatement(nodep); if (!m_funcp) { @@ -4871,7 +4867,7 @@ private: } } - virtual void visit(AstFuncRef* nodep) override { + void visit(AstFuncRef* nodep) override { visit(static_cast(nodep)); nodep->dtypeFrom(nodep->taskp()); // if (debug()) nodep->dumpTree(cout, " FuncOut: "); @@ -5041,7 +5037,7 @@ private: } } } - virtual void visit(AstNodeFTaskRef* nodep) override { + void visit(AstNodeFTaskRef* nodep) override { // For arguments, is assignment-like context; see IEEE rules in AstNodeAssign // Function hasn't been widthed, so make it so. UINFO(5, " FTASKREF " << nodep << endl); @@ -5052,13 +5048,13 @@ private: processFTaskRefArgs(nodep); nodep->didWidth(true); } - virtual void visit(AstNodeProcedure* nodep) override { + void visit(AstNodeProcedure* nodep) override { assertAtStatement(nodep); m_procedurep = nodep; userIterateChildren(nodep, nullptr); m_procedurep = nullptr; } - virtual void visit(AstWith* nodep) override { + void visit(AstWith* nodep) override { // Should otherwise be underneath a method call AstNodeDType* const vdtypep = m_vup->dtypeNullSkipRefp(); { @@ -5076,7 +5072,7 @@ private: nodep->dtypep()); } } - virtual void visit(AstLambdaArgRef* nodep) override { + void visit(AstLambdaArgRef* nodep) override { UASSERT_OBJ(m_withp, nodep, "LambdaArgRef not underneath 'with' lambda"); if (nodep->index()) { nodep->dtypeFrom(m_withp->indexArgRefp()); @@ -5084,21 +5080,21 @@ private: nodep->dtypeFrom(m_withp->valueArgRefp()); } } - virtual void visit(AstNetlist* nodep) override { + void visit(AstNetlist* nodep) override { // Iterate modules backwards, in bottom-up order. That's faster userIterateChildrenBackwards(nodep, nullptr); } //-------------------- // Default - virtual void visit(AstNodeMath* nodep) override { + void visit(AstNodeMath* nodep) override { if (!nodep->didWidth()) { nodep->v3fatalSrc( "Visit function missing? Widthed function missing for math node: " << nodep); } userIterateChildren(nodep, nullptr); } - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { // Default: Just iterate UASSERT_OBJ(!m_vup, nodep, "Visit function missing? Widthed expectation for this node: " << nodep); @@ -5120,7 +5116,7 @@ private: iterateCheck(nodep, "LHS", nodep->lhsp(), SELF, FINAL, subDTypep, EXTEND_EXP); } } - virtual void visit(AstIToRD* nodep) override { + void visit(AstIToRD* nodep) override { // Real: Output real // LHS presumed self-determined, then coerced to real if (m_vup->prelim()) { // First stage evaluation @@ -5134,7 +5130,7 @@ private: } } } - virtual void visit(AstISToRD* nodep) override { + void visit(AstISToRD* nodep) override { // Real: Output real // LHS presumed self-determined, then coerced to real if (m_vup->prelim()) { // First stage evaluation @@ -5807,7 +5803,8 @@ private: "Node has no type"); // Perhaps forgot to do a prelim visit on it? // // For DOUBLE under a logical op, add implied test against zero, never a warning - if (underp && underp->isDouble()) { + AstNodeDType* const underVDTypep = underp ? underp->dtypep()->skipRefp() : nullptr; + if (underp && underVDTypep->isDouble()) { UINFO(6, " spliceCvtCmpD0: " << underp << endl); VNRelinker linker; underp->unlinkFrBack(&linker); @@ -5815,13 +5812,12 @@ private: = new AstNeqD(nodep->fileline(), underp, new AstConst(nodep->fileline(), AstConst::RealDouble(), 0.0)); linker.relink(newp); - } else if (VN_IS(underp->dtypep(), ClassRefDType) - || (VN_IS(underp->dtypep(), BasicDType) - && VN_AS(underp->dtypep(), BasicDType)->keyword() - == VBasicDTypeKwd::CHANDLE)) { + } else if (VN_IS(underVDTypep, ClassRefDType) + || (VN_IS(underVDTypep, BasicDType) + && VN_AS(underVDTypep, BasicDType)->keyword() == VBasicDTypeKwd::CHANDLE)) { // Allow warning-free "if (handle)" VL_DO_DANGLING(fixWidthReduce(underp), underp); // Changed - } else if (!underp->dtypep()->basicp()) { + } else if (!underVDTypep->basicp()) { nodep->v3error("Logical operator " << nodep->prettyTypeName() << " expects a non-complex data type on the " << side << "."); @@ -5962,7 +5958,7 @@ private: } if ((VN_IS(nodep, Add) && underp->width() == 1 && underp->isOne()) || (VN_IS(nodep, Sub) && underp->width() == 1 && underp->isOne() - && 0 == strcmp(side, "RHS"))) { + && 0 == std::strcmp(side, "RHS"))) { // "foo + 1'b1", or "foo - 1'b1" are very common, people assume // they extend correctly warnOn = false; @@ -6281,7 +6277,7 @@ private: VNumRange declRange; // ranged() set false for (int i = 1; i <= dim; ++i) { // UINFO(9, " dim at "<declRange(); if (i < dim) dtypep = adtypep->subDTypep()->skipRefp(); @@ -6359,7 +6355,7 @@ private: varp->isStatic(true); varp->valuep(initp); // Add to root, as don't know module we are in, and aids later structure sharing - v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(varp); + v3Global.rootp()->dollarUnitPkgAddp()->addStmtsp(varp); // Element 0 is a non-index and has speced values initp->addValuep(dimensionValue(nodep->fileline(), nodep, attrType, 0)); for (unsigned i = 1; i < msbdim + 1; ++i) { @@ -6424,7 +6420,7 @@ private: varp->isStatic(true); varp->valuep(initp); // Add to root, as don't know module we are in, and aids later structure sharing - v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(varp); + v3Global.rootp()->dollarUnitPkgAddp()->addStmtsp(varp); // Default for all unspecified values if (attrType == VAttrType::ENUM_NAME) { @@ -6725,18 +6721,12 @@ public: AstNode* mainAcceptEdit(AstNode* nodep) { return userIterateSubtreeReturnEdits(nodep, WidthVP(SELF, BOTH).p()); } - virtual ~WidthVisitor() override = default; + ~WidthVisitor() override = default; }; //###################################################################### // Width class functions -int V3Width::debug() { - static int level = -1; - if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__); - return level; -} - void V3Width::width(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { @@ -6747,7 +6737,7 @@ void V3Width::width(AstNetlist* nodep) { WidthRemoveVisitor rvisitor; (void)rvisitor.mainAcceptEdit(nodep); } // Destruct before checking - V3Global::dumpCheckGlobalTree("width", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("width", 0, dumpTree() >= 3); } //! Single node parameter propagation @@ -6783,5 +6773,5 @@ AstNode* V3Width::widthGenerateParamsEdit( void V3Width::widthCommit(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { WidthCommitVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("widthcommit", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6); + V3Global::dumpCheckGlobalTree("widthcommit", 0, dumpTree() >= 6); } diff --git a/src/V3Width.h b/src/V3Width.h index 2d6cfb9d7..6a0261d9e 100644 --- a/src/V3Width.h +++ b/src/V3Width.h @@ -27,7 +27,6 @@ class AstNode; class V3Width final { public: - static int debug(); static void width(AstNetlist* nodep); static AstNode* widthParamsEdit(AstNode* nodep); static AstNode* widthGenerateParamsEdit(AstNode* nodep); diff --git a/src/V3WidthCommit.h b/src/V3WidthCommit.h index 5b784387d..ca2f9a584 100644 --- a/src/V3WidthCommit.h +++ b/src/V3WidthCommit.h @@ -35,8 +35,9 @@ /// This step is only called on real V3Width, not intermediate e.g. widthParams class WidthRemoveVisitor final : public VNVisitor { -private: // METHODS + VL_DEFINE_DEBUG_FUNCTIONS; + void replaceWithSignedVersion(AstNode* nodep, AstNode* newp) { UINFO(6, " Replace " << nodep << " w/ " << newp << endl); nodep->replaceWith(newp); @@ -45,18 +46,18 @@ private: } // VISITORS - virtual void visit(AstSigned* nodep) override { + void visit(AstSigned* nodep) override { VL_DO_DANGLING(replaceWithSignedVersion(nodep, nodep->lhsp()->unlinkFrBack()), nodep); } - virtual void visit(AstUnsigned* nodep) override { + void visit(AstUnsigned* nodep) override { VL_DO_DANGLING(replaceWithSignedVersion(nodep, nodep->lhsp()->unlinkFrBack()), nodep); } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS WidthRemoveVisitor() = default; - virtual ~WidthRemoveVisitor() override = default; + ~WidthRemoveVisitor() override = default; AstNode* mainAcceptEdit(AstNode* nodep) { return iterateSubtreeReturnEdits(nodep); } }; @@ -74,6 +75,8 @@ class WidthCommitVisitor final : public VNVisitor { public: // METHODS + VL_DEFINE_DEBUG_FUNCTIONS; + static AstConst* newIfConstCommitSize(AstConst* nodep) { if (((nodep->dtypep()->width() != nodep->num().width()) || !nodep->num().sized()) && !nodep->num().isString()) { // Need to force the number from unsized to sized @@ -151,7 +154,7 @@ private: } // VISITORS - virtual void visit(AstNodeModule* nodep) override { + void visit(AstNodeModule* nodep) override { VL_RESTORER(m_modp); { m_modp = nodep; @@ -159,7 +162,7 @@ private: editDType(nodep); } } - virtual void visit(AstConst* nodep) override { + void visit(AstConst* nodep) override { UASSERT_OBJ(nodep->dtypep(), nodep, "No dtype"); iterate(nodep->dtypep()); // Do datatype first if (AstConst* const newp = newIfConstCommitSize(nodep)) { @@ -172,15 +175,15 @@ private: } editDType(nodep); } - virtual void visit(AstNodeDType* nodep) override { // + void visit(AstNodeDType* nodep) override { // visitIterateNodeDType(nodep); } - virtual void visit(AstNodeUOrStructDType* nodep) override { + void visit(AstNodeUOrStructDType* nodep) override { if (nodep->user1SetOnce()) return; // Process once visitIterateNodeDType(nodep); nodep->clearCache(); } - virtual void visit(AstParamTypeDType* nodep) override { + void visit(AstParamTypeDType* nodep) override { if (nodep->user1SetOnce()) return; // Process once visitIterateNodeDType(nodep); // Move to type table as all dtype pointers must resolve there @@ -199,7 +202,7 @@ private: nodep->virtRefDTypep(editOneDType(nodep->virtRefDTypep())); nodep->virtRefDType2p(editOneDType(nodep->virtRefDType2p())); } - virtual void visit(AstNodeFTask* nodep) override { + void visit(AstNodeFTask* nodep) override { iterateChildren(nodep); editDType(nodep); if (nodep->classMethod() && nodep->pureVirtual() && VN_IS(m_modp, Class) @@ -208,28 +211,28 @@ private: "Illegal to have 'pure virtual' in non-virtual class (IEEE 1800-2017 8.21)"); } } - virtual void visit(AstNodeVarRef* nodep) override { + void visit(AstNodeVarRef* nodep) override { iterateChildren(nodep); editDType(nodep); classEncapCheck(nodep, nodep->varp(), VN_CAST(nodep->classOrPackagep(), Class)); } - virtual void visit(AstNodeFTaskRef* nodep) override { + void visit(AstNodeFTaskRef* nodep) override { iterateChildren(nodep); editDType(nodep); classEncapCheck(nodep, nodep->taskp(), VN_CAST(nodep->classOrPackagep(), Class)); } - virtual void visit(AstMemberSel* nodep) override { + void visit(AstMemberSel* nodep) override { iterateChildren(nodep); editDType(nodep); if (auto* const classrefp = VN_CAST(nodep->fromp()->dtypep(), ClassRefDType)) { classEncapCheck(nodep, nodep->varp(), classrefp->classp()); } // else might be struct, etc } - virtual void visit(AstNodePreSel* nodep) override { // LCOV_EXCL_LINE + void visit(AstNodePreSel* nodep) override { // LCOV_EXCL_LINE // This check could go anywhere after V3Param nodep->v3fatalSrc("Presels should have been removed before this point"); } - virtual void visit(AstNode* nodep) override { + void visit(AstNode* nodep) override { iterateChildren(nodep); editDType(nodep); } @@ -243,7 +246,7 @@ public: // Don't want to repairCache, as all needed nodes have been added back in // a repair would prevent dead nodes from being detected } - virtual ~WidthCommitVisitor() override = default; + ~WidthCommitVisitor() override = default; }; //###################################################################### diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp index d958f6d52..174d01a36 100644 --- a/src/V3WidthSel.cpp +++ b/src/V3WidthSel.cpp @@ -34,6 +34,8 @@ #include "V3Global.h" #include "V3Width.h" +VL_DEFINE_DEBUG_FUNCTIONS; + //###################################################################### // Width state, as a visitor of each AstNode @@ -47,7 +49,6 @@ private: #define iterateChildren DO_NOT_iterateChildern_IN_V3WidthSel // METHODS - VL_DEBUG_FUNC; // Declare debug() void checkConstantOrReplace(AstNode* nodep, const string& message) { // See also V3Width::checkConstantOrReplace @@ -202,7 +203,7 @@ private: // VISITORS // If adding new visitors, ensure V3Width's visit(TYPE) calls into here - virtual void visit(AstSelBit* nodep) override { + void visit(AstSelBit* nodep) override { // Select of a non-width specified part of an array, i.e. "array[2]" // This select style has a lsb and msb (no user specified width) UINFO(6, "SELBIT " << nodep << endl); @@ -330,7 +331,7 @@ private: } if (!rhsp->backp()) VL_DO_DANGLING(pushDeletep(rhsp), rhsp); } - virtual void visit(AstSelExtract* nodep) override { + void visit(AstSelExtract* nodep) override { // Select of a range specified part of an array, i.e. "array[2:3]" // SELEXTRACT(from,msb,lsb) -> SEL(from, lsb, 1+msb-lsb) // This select style has a (msb or lsb) and width @@ -524,8 +525,8 @@ private: // up array: lsb/hi -: width const int32_t msb = VN_IS(nodep, SelPlus) ? rhs + width - 1 : rhs; const int32_t lsb = VN_IS(nodep, SelPlus) ? rhs : rhs - width + 1; - AstSliceSel* const newp = new AstSliceSel( - nodep->fileline(), fromp, VNumRange(msb, lsb, fromRange.littleEndian())); + AstSliceSel* const newp = new AstSliceSel{ + nodep->fileline(), fromp, VNumRange{msb, lsb, fromRange.littleEndian()}}; nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } else { @@ -584,13 +585,13 @@ private: if (!rhsp->backp()) VL_DO_DANGLING(pushDeletep(rhsp), rhsp); if (!widthp->backp()) VL_DO_DANGLING(pushDeletep(widthp), widthp); } - virtual void visit(AstSelPlus* nodep) override { replaceSelPlusMinus(nodep); } - virtual void visit(AstSelMinus* nodep) override { replaceSelPlusMinus(nodep); } + void visit(AstSelPlus* nodep) override { replaceSelPlusMinus(nodep); } + void visit(AstSelMinus* nodep) override { replaceSelPlusMinus(nodep); } // If adding new visitors, ensure V3Width's visit(TYPE) calls into here //-------------------- // Default - virtual void visit(AstNode* nodep) override { // LCOV_EXCL_LINE + void visit(AstNode* nodep) override { // LCOV_EXCL_LINE // See notes above; we never iterate nodep->v3fatalSrc("Shouldn't iterate in V3WidthSel"); } @@ -598,7 +599,7 @@ private: public: // CONSTRUCTORS WidthSelVisitor() = default; - virtual ~WidthSelVisitor() override = default; + ~WidthSelVisitor() override = default; AstNode* mainAcceptEdit(AstNode* nodep) { return iterateSubtreeReturnEdits(nodep); } }; diff --git a/src/Verilator.cpp b/src/Verilator.cpp index b5d2df2cb..448bf735d 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -103,6 +103,8 @@ #include +VL_DEFINE_DEBUG_FUNCTIONS; + V3Global v3Global; static void reportStatsIfEnabled() { @@ -563,7 +565,7 @@ static void verilate(const string& argString) { UINFO(1, "Option --verilate: Start Verilation\n"); // Can we skip doing everything if times are ok? - V3File::addSrcDepend(v3Global.opt.bin()); + V3File::addSrcDepend(v3Global.opt.buildDepBin()); if (v3Global.opt.skipIdentical().isTrue() && V3File::checkTimes(v3Global.opt.hierTopDataDir() + "/" + v3Global.opt.prefix() + "__verFiles.dat", @@ -607,7 +609,7 @@ static void verilate(const string& argString) { } // Final steps - V3Global::dumpCheckGlobalTree("final", 990, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + V3Global::dumpCheckGlobalTree("final", 990, dumpTree() >= 3); V3Error::abortIfErrors(); @@ -663,11 +665,7 @@ static string buildMakeCmd(const string& makefile, const string& target) { cmd << v3Global.opt.getenvMAKE(); cmd << " -C " << v3Global.opt.makeDir(); cmd << " -f " << makefile; - if (jobs == 0) { - cmd << " -j"; - } else if (jobs > 1) { - cmd << " -j " << jobs; - } + if (jobs > 0) cmd << " -j " << jobs; for (const string& flag : makeFlags) cmd << ' ' << flag; if (!target.empty()) cmd << ' ' << target; @@ -718,9 +716,9 @@ int main(int argc, char** argv, char** /*env*/) { V3PreShell::boot(); // Command option parsing - v3Global.opt.bin(argv[0]); + v3Global.opt.buildDepBin(argv[0]); const string argString = V3Options::argString(argc - 1, argv + 1); - v3Global.opt.parseOpts(new FileLine(FileLine::commandLineFilename()), argc - 1, argv + 1); + v3Global.opt.parseOpts(new FileLine{FileLine::commandLineFilename()}, argc - 1, argv + 1); // Validate settings (aka Boost.Program_options) v3Global.opt.notify(); diff --git a/src/VlcMain.cpp b/src/VlcMain.cpp index f4f6717ca..5f1b01ec5 100644 --- a/src/VlcMain.cpp +++ b/src/VlcMain.cpp @@ -23,14 +23,18 @@ #include "verilatedos.h" -// Cheat for speed and compile .cpp files into one object +// Cheat for speed and compile .cpp files into one object TODO: Reconsider #define V3ERROR_NO_GLOBAL_ +#include "V3Error.h" +static int debug() { return V3Error::debugDefault(); } #include "V3Error.cpp" #include "V3String.cpp" #define V3OPTION_PARSER_NO_VOPTION_BOOL +// clang-format off #include "V3OptionParser.cpp" #include "V3Os.cpp" #include "VlcTop.cpp" +// clanf-format on #include "VlcOptions.h" #include "VlcTop.h" diff --git a/src/VlcPoint.h b/src/VlcPoint.h index b5c9598fc..1b59b39f2 100644 --- a/src/VlcPoint.h +++ b/src/VlcPoint.h @@ -102,6 +102,8 @@ private: std::vector m_points; //< List of all points uint64_t m_numPoints = 0; //< Total unique points + static int debug() { return V3Error::debugDefault(); } + public: // ITERATORS using ByName = NameMap; diff --git a/src/VlcTest.h b/src/VlcTest.h index 2c85950dc..0ceb7d340 100644 --- a/src/VlcTest.h +++ b/src/VlcTest.h @@ -93,6 +93,8 @@ private: // MEMBERS ByName m_tests; //< List of all tests + static int debug() { return V3Error::debugDefault(); } + public: // ITERATORS using iterator = ByName::iterator; diff --git a/src/astgen b/src/astgen index 44529a0e4..dbe6968e0 100755 --- a/src/astgen +++ b/src/astgen @@ -4,18 +4,184 @@ import argparse import glob +import os import re import sys +import textwrap # from pprint import pprint, pformat -Types = [] -Classes = {} -Children = {} + +class Node: + + def __init__(self, name, superClass, file, lineno): + self._name = name + self._superClass = superClass + self._subClasses = [] # Initially list, but tuple after completion + self._allSuperClasses = None # Computed on demand after completion + self._allSubClasses = None # Computed on demand after completion + self._typeId = None # Concrete type identifier number for leaf classes + self._typeIdMin = None # Lowest type identifier number for class + self._typeIdMax = None # Highest type identifier number for class + self._file = file # File this class is defined in + self._lineno = lineno # Line this class is defined on + self._ordIdx = None # Ordering index of this class + self._arity = -1 # Arity of node + self._ops = {} # Operands of node + + @property + def name(self): + return self._name + + @property + def superClass(self): + return self._superClass + + @property + def isRoot(self): + return self.superClass is None + + @property + def isCompleted(self): + return isinstance(self._subClasses, tuple) + + @property + def file(self): + return self._file + + @property + def lineno(self): + return self._lineno + + # Pre completion methods + def addSubClass(self, subClass): + assert not self.isCompleted + self._subClasses.append(subClass) + + def addOp(self, n, name, monad, kind): + assert 1 <= n <= 4 + self._ops[n] = (name, monad, kind) + self._arity = max(self._arity, n) + + def getOp(self, n): + assert 1 <= n <= 4 + op = self._ops.get(n, None) + if op is not None: + return op + if not self.isRoot: + return self.superClass.getOp(n) + return None + + # Computes derived properties over entire class hierarchy. + # No more changes to the hierarchy are allowed once this was called + def complete(self, typeId=0, ordIdx=0): + assert not self.isCompleted + # Sort sub-classes and convert to tuple, which marks completion + self._subClasses = tuple( + sorted(self._subClasses, + key=lambda _: (bool(_._subClasses), _.name))) + + self._ordIdx = ordIdx + ordIdx = ordIdx + 1 + + if self.isRoot: + self._arity = 0 + else: + self._arity = max(self._arity, self._superClass.arity) + + # Leaves + if self.isLeaf: + self._typeId = typeId + return typeId + 1, ordIdx + + # Non-leaves + for subClass in self._subClasses: + typeId, ordIdx = subClass.complete(typeId, ordIdx) + return typeId, ordIdx + + # Post completion methods + @property + def subClasses(self): + assert self.isCompleted + return self._subClasses + + @property + def isLeaf(self): + assert self.isCompleted + return not self.subClasses + + @property + def allSuperClasses(self): + assert self.isCompleted + if self._allSuperClasses is None: + if self.superClass is None: + self._allSuperClasses = () + else: + self._allSuperClasses = self.superClass.allSuperClasses + ( + self.superClass, ) + return self._allSuperClasses + + @property + def allSubClasses(self): + assert self.isCompleted + if self._allSubClasses is None: + if self.isLeaf: + self._allSubClasses = () + else: + self._allSubClasses = self.subClasses + tuple( + _ for subClass in self.subClasses + for _ in subClass.allSubClasses) + return self._allSubClasses + + @property + def typeId(self): + assert self.isCompleted + assert self.isLeaf + return self._typeId + + @property + def typeIdMin(self): + assert self.isCompleted + if self.isLeaf: + return self.typeId + if self._typeIdMin is None: + self._typeIdMin = min(_.typeIdMin for _ in self.allSubClasses) + return self._typeIdMin + + @property + def typeIdMax(self): + assert self.isCompleted + if self.isLeaf: + return self.typeId + if self._typeIdMax is None: + self._typeIdMax = max(_.typeIdMax for _ in self.allSubClasses) + return self._typeIdMax + + @property + def ordIdx(self): + assert self.isCompleted + return self._ordIdx + + @property + def arity(self): + assert self.isCompleted + return self._arity + + def isSubClassOf(self, other): + assert self.isCompleted + if self is other: + return True + return self in other.allSubClasses + + +Nodes = {} +SortedNodes = None + ClassRefs = {} Stages = {} class Cpt: + def __init__(self): self.did_out_tree = False self.in_filename = "" @@ -111,7 +277,7 @@ class Cpt: self.error("Can't parse from function: " + func) typen = match.group(1) subnodes = match.group(2) - if not subclasses_of(typen): + if Nodes[typen].isRoot: self.error("Unknown AstNode typen: " + typen + ": in " + func) mif = "" @@ -166,7 +332,7 @@ class Cpt: elif match_skip: typen = match_skip.group(1) self.tree_skip_visit[typen] = 1 - if typen not in Classes: + if typen not in Nodes: self.error("Unknown node type: " + typen) else: @@ -296,12 +462,13 @@ class Cpt: self.print( " // Bottom class up, as more simple transforms are generally better\n" ) - for typen in sorted(Classes.keys()): + for node in SortedNodes: out_for_type_sc = [] out_for_type = [] - bases = subclasses_of(typen) - bases.append(typen) - for base in bases: + classes = list(node.allSuperClasses) + classes.append(node) + for base in classes: + base = base.name if base not in self.treeop: continue for typefunc in self.treeop[base]: @@ -328,23 +495,25 @@ class Cpt: if len(out_for_type_sc) > 0: # Short-circuited types self.print( " // Generated by astgen with short-circuiting\n" + - " virtual void visit(Ast" + typen + + " void visit(Ast" + node.name + "* nodep) override {\n" + " iterateAndNextNull(nodep->lhsp());\n" + "".join(out_for_type_sc)) if out_for_type[0]: self.print(" iterateAndNextNull(nodep->rhsp());\n") - if is_subclass_of(typen, "NodeTriop"): + if node.isSubClassOf(Nodes["NodeTriop"]): self.print( " iterateAndNextNull(nodep->thsp());\n") self.print("".join(out_for_type) + " }\n") elif len(out_for_type) > 0: # Other types with something to print - skip = typen in self.tree_skip_visit + skip = node.name in self.tree_skip_visit gen = "Gen" if skip else "" + virtual = "virtual " if skip else "" override = "" if skip else " override" self.print( - " // Generated by astgen\n" + " virtual void visit" + - gen + "(Ast" + typen + "* nodep)" + override + " {\n" + + " // Generated by astgen\n" + " " + virtual + + "void visit" + gen + "(Ast" + node.name + "* nodep)" + + override + " {\n" + ("" if skip else " iterateChildren(nodep);\n") + ''.join(out_for_type) + " }\n") @@ -353,26 +522,131 @@ class Cpt: ###################################################################### +def partitionAndStrip(string, separator): + return map(lambda _: _.strip(), string.partition(separator)) + + +def parseOpType(string): + match = re.match(r'^(\w+)\[(\w+)\]$', string) + if match: + monad, kind = match.groups() + if monad not in ("Optional", "List"): + return None + kind = parseOpType(kind) + if not kind or kind[0]: + return None + return monad, kind[1] + if re.match(r'^Ast(\w+)$', string): + return "", string[3:] + return None + + def read_types(filename): + hasErrors = False + + def error(lineno, message): + nonlocal hasErrors + print(filename + ":" + str(lineno) + ": %Error: " + message, + file=sys.stderr) + hasErrors = True + + node = None + hasAstgenMembers = False + + def checkFinishedNode(node): + nonlocal hasAstgenMembers + if not node: + return + if not hasAstgenMembers: + error( + node.lineno, "'Ast" + node.name + + "' does not contain 'ASTGEN_MEMBERS_" + node.name + ";'") + hasAstgenMembers = False + with open(filename) as fh: - for line in fh: - line = re.sub(r'//.*$', '', line) - if re.match(r'^\s*$', line): + for (lineno, line) in enumerate(fh, start=1): + line = line.strip() + if not line: continue + match = re.search(r'^\s*(class|struct)\s*(\S+)', line) if match: classn = match.group(2) match = re.search(r':\s*public\s+(\S+)', line) supern = match.group(1) if match else "" - assert classn != "AstNode" or supern == "", "AstNode can't have a superclass" - if re.search(r'Ast', supern) or classn == "AstNode": + if re.search(r'Ast', supern): classn = re.sub(r'^Ast', '', classn) supern = re.sub(r'^Ast', '', supern) - Classes[classn] = supern - if supern != '': - if supern not in Children: - Children[supern] = {} - Children[supern][classn] = 1 + if not supern: + sys.exit("%Error: 'Ast{}' has no super-class".format( + classn)) + checkFinishedNode(node) + superClass = Nodes[supern] + node = Node(classn, superClass, filename, lineno) + superClass.addSubClass(node) + Nodes[classn] = node + if not node: + continue + + if re.match(r'^\s*ASTGEN_MEMBERS_' + node.name + ';', line): + hasAstgenMembers = True + match = re.match(r'^\s*//\s*@astgen\s+(.*)$', line) + if match: + decl = re.sub(r'//.*$', '', match.group(1)) + what, sep, rest = partitionAndStrip(decl, ":=") + what = re.sub(r'\s+', ' ', what) + if not sep: + error( + lineno, + "Malformed '@astgen' directive (expecting ' := '): " + + decl) + elif what in ("op1", "op2", "op3", "op4"): + n = int(what[-1]) + ident, sep, kind = partitionAndStrip(rest, ":") + ident = ident.strip() + if not sep or not re.match(r'^\w+$', ident): + error( + lineno, "Malformed '@astgen " + what + + "' directive (expecting '" + what + + " := : ': " + decl) + else: + kind = parseOpType(kind) + if not kind: + error( + lineno, "Bad type for '@astgen " + what + + "' (expecting Ast*, Optional[Ast*], or List[Ast*]):" + + decl) + elif node.getOp(n) is not None: + error( + lineno, "Already defined " + what + " for " + + node.name) + else: + node.addOp(n, ident, *kind) + elif what in ("alias op1", "alias op2", "alias op3", + "alias op4"): + n = int(what[-1]) + ident = rest.strip() + if not re.match(r'^\w+$', ident): + error( + lineno, "Malformed '@astgen " + what + + "' directive (expecting '" + what + + " := ': " + decl) + else: + op = node.getOp(n) + if op is None: + error(lineno, + "Alaised op" + str(n) + " is not defined") + else: + node.addOp(n, ident, *op[1:]) + else: + line = re.sub(r'//.*$', '', line) + if re.match(r'.*[Oo]p[1-9].*', line): + error(lineno, + "Use generated accessors to access op operands") + + checkFinishedNode(node) + if hasErrors: + sys.exit("%Error: Stopping due to errors reported above") def read_stages(filename): @@ -424,37 +698,6 @@ def open_file(filename): return fh -def subclasses_of(typen): - cllist = [] - subclass = Classes[typen] - while True: - if subclass not in Classes: - break - cllist.append(subclass) - subclass = Classes[subclass] - - cllist.reverse() - return cllist - - -def children_of(typen): - cllist = [] - todo = [] - todo.append(typen) - while len(todo) != 0: - subclass = todo.pop(0) - if subclass in Children: - for child in sorted(Children[subclass].keys()): - todo.append(child) - cllist.append(child) - - return cllist - - -def is_subclass_of(typen, what): - return typen == what or (typen in children_of(what)) - - # --------------------------------------------------------------------- @@ -468,20 +711,20 @@ def write_report(filename): fh.write(" " + classn + "\n") fh.write("\nClasses:\n") - for typen in sorted(Classes.keys()): - fh.write(" class Ast%-17s\n" % typen) + for node in SortedNodes: + fh.write(" class Ast%-17s\n" % node.name) + fh.write(" arity: {}\n".format(node.arity)) fh.write(" parent: ") - for subclass in subclasses_of(typen): - if subclass != 'Node': - fh.write("Ast%-12s " % subclass) + for superClass in node.allSuperClasses: + if not superClass.isRoot: + fh.write("Ast%-12s " % superClass.name) fh.write("\n") fh.write(" childs: ") - for subclass in children_of(typen): - if subclass != 'Node': - fh.write("Ast%-12s " % subclass) + for subClass in node.allSubClasses: + fh.write("Ast%-12s " % subClass.name) fh.write("\n") - if ("Ast" + typen) in ClassRefs: # pylint: disable=superfluous-parens - refs = ClassRefs["Ast" + typen] + if ("Ast" + node.name) in ClassRefs: # pylint: disable=superfluous-parens + refs = ClassRefs["Ast" + node.name] fh.write(" newed: ") for stage in sorted(refs['newed'].keys(), key=lambda val: Stages[val] @@ -500,27 +743,27 @@ def write_report(filename): def write_classes(filename): with open_file(filename) as fh: fh.write("class AstNode;\n") - for typen in sorted(Classes.keys()): - fh.write("class Ast%-17s // " % (typen + ";")) - for subclass in subclasses_of(typen): - fh.write("Ast%-12s " % subclass) + for node in SortedNodes: + fh.write("class Ast%-17s // " % (node.name + ";")) + for superClass in node.allSuperClasses: + fh.write("Ast%-12s " % superClass.name) fh.write("\n") def write_visitor_decls(filename): with open_file(filename) as fh: - for typen in sorted(Classes.keys()): - if typen != "Node": - fh.write("virtual void visit(Ast" + typen + "*);\n") + for node in SortedNodes: + if not node.isRoot: + fh.write("virtual void visit(Ast" + node.name + "*);\n") def write_visitor_defns(filename): with open_file(filename) as fh: - for typen in sorted(Classes.keys()): - if typen != "Node": - base = Classes[typen] - fh.write("void VNVisitor::visit(Ast" + typen + - "* nodep) { visit(static_cast(nodep)); }\n") @@ -528,75 +771,51 @@ def write_impl(filename): with open_file(filename) as fh: fh.write("\n") fh.write("// For internal use. They assume argument is not nullptr.\n") - for typen in sorted(Classes.keys()): + for node in SortedNodes: fh.write("template<> inline bool AstNode::privateTypeTest(const AstNode* nodep) { ") - if typen == "Node": + node.name + ">(const AstNode* nodep) { ") + if node.isRoot: fh.write("return true; ") else: fh.write("return ") - if re.search(r'^Node', typen): + if not node.isLeaf: fh.write( "static_cast(nodep->type()) >= static_cast(VNType::first" - + typen + ") && ") + + node.name + ") && ") fh.write( "static_cast(nodep->type()) <= static_cast(VNType::last" - + typen + "); ") + + node.name + "); ") else: - fh.write("nodep->type() == VNType::at" + typen + "; ") + fh.write("nodep->type() == VNType::at" + node.name + "; ") fh.write("}\n") -def write_type_enum(fh, typen, idx, processed, kind, indent): - # Skip this if it has already been processed - if typen in processed: - return idx - # Mark processed - processed[typen] = 1 - - # The last used index - last = None - - if not re.match(r'^Node', typen): - last = idx - if kind == "concrete-enum": - fh.write(" " * (indent * 4) + "at" + typen + " = " + str(idx) + - ",\n") - elif kind == "concrete-ascii": - fh.write(" " * (indent * 4) + "\"" + typen.upper() + "\",\n") - idx += 1 - elif kind == "abstract-enum": - fh.write(" " * (indent * 4) + "first" + typen + " = " + str(idx) + - ",\n") - - if typen in Children: - for child in sorted(Children[typen].keys()): - (idx, last) = write_type_enum(fh, child, idx, processed, kind, - indent) - - if re.match(r'^Node', typen) and kind == "abstract-enum": - fh.write(" " * (indent * 4) + "last" + typen + " = " + str(last) + - ",\n") - - return [idx, last] - - def write_types(filename): with open_file(filename) as fh: fh.write(" enum en : uint16_t {\n") - (final, ignored) = write_type_enum( # pylint: disable=W0612 - fh, "Node", 0, {}, "concrete-enum", 2) - fh.write(" _ENUM_END = " + str(final) + "\n") + for node in sorted(filter(lambda _: _.isLeaf, SortedNodes), + key=lambda _: _.typeId): + fh.write(" at" + node.name + " = " + str(node.typeId) + + ",\n") + fh.write(" _ENUM_END = " + str(Nodes["Node"].typeIdMax + 1) + + "\n") fh.write(" };\n") fh.write(" enum bounds : uint16_t {\n") - write_type_enum(fh, "Node", 0, {}, "abstract-enum", 2) + for node in sorted(filter(lambda _: not _.isLeaf, SortedNodes), + key=lambda _: _.typeIdMin): + fh.write(" first" + node.name + " = " + + str(node.typeIdMin) + ",\n") + fh.write(" last" + node.name + " = " + str(node.typeIdMax) + + ",\n") fh.write(" _BOUNDS_END\n") fh.write(" };\n") fh.write(" const char* ascii() const {\n") fh.write(" static const char* const names[_ENUM_END + 1] = {\n") - write_type_enum(fh, "Node", 0, {}, "concrete-ascii", 3) + for node in sorted(filter(lambda _: _.isLeaf, SortedNodes), + key=lambda _: _.typeId): + fh.write(" \"" + node.name.upper() + "\",\n") fh.write(" \"_ENUM_END\"\n") fh.write(" };\n") fh.write(" return names[m_e];\n") @@ -605,45 +824,169 @@ def write_types(filename): def write_yystype(filename): with open_file(filename) as fh: - for typen in sorted(Classes.keys()): - fh.write("Ast{t}* {m}p;\n".format(t=typen, - m=typen[0].lower() + typen[1:])) + for node in SortedNodes: + fh.write("Ast{t}* {m}p;\n".format(t=node.name, + m=node.name[0].lower() + + node.name[1:])) def write_macros(filename): with open_file(filename) as fh: - typen = "None" - base = "None" - in_filename = "V3AstNodes.h" - ifile = Args.I + "/" + in_filename - with open(ifile) as ifh: - for (lineno, line) in enumerate(ifh, 1): - # Drop expanded macro definitions - but keep empty line so compiler - # message locations are accurate - line = re.sub(r'^\s*#(define|undef)\s+ASTGEN_.*$', '', line) + def emitBlock(pattern, **fmt): + fh.write( + textwrap.indent(textwrap.dedent(pattern), + " ").format(**fmt).replace("\n", " \\\n")) - # Track current node type and base class - match = re.search( - r'\s*class\s*Ast(\S+)\s*(final|VL_NOT_FINAL)?\s*:\s*(public)?\s*(AstNode\S*)', - line) - if match: - typen = match.group(1) - base = match.group(4) - if not typen.startswith("Node"): - macro = "#define ASTGEN_SUPER_{t}(...) {b}(VNType::at{t}, __VA_ARGS__)\n" \ - .format(b=base, t=typen) - fh.write(macro) + for node in SortedNodes: + fh.write("#define ASTGEN_MEMBERS_{t} \\\n".format(t=node.name)) + emitBlock('''\ + static Ast{t}* cloneTreeNull(Ast{t}* nodep, bool cloneNextLink) {{ + return nodep ? nodep->cloneTree(cloneNextLink) : nullptr; + }} + Ast{t}* cloneTree(bool cloneNext) {{ + return static_cast(AstNode::cloneTree(cloneNext)); + }} + Ast{t}* clonep() const {{ return static_cast(AstNode::clonep()); }} + Ast{t}* addNext(Ast{t}* nodep) {{ return static_cast(AstNode::addNext(this, nodep)); }} + ''', + t=node.name) - match = re.search(r"ASTGEN_SUPER_(\w+)", line) - if match: - if typen != match.group(1): - print(( - "V3AstNodes.h:{l} ERROR: class Ast{t} calls wrong superclass " - + - "constructor macro (should call ASTGEN_SUPER_{t})" - ).format(l=lineno, t=typen)) - sys.exit(1) + if node.isLeaf: + emitBlock('''\ + void accept(VNVisitor& v) override {{ v.visit(this); }} + AstNode* clone() override {{ return new Ast{t}(*this); }} + ''', + t=node.name) + + for n in (1, 2, 3, 4): + op = node.getOp(n) + if not op: + continue + name, monad, kind = op + retrieve = ("VN_AS(op{n}p(), {kind})" if kind != "Node" else + "op{n}p()").format(n=n, kind=kind) + if monad == "List": + emitBlock('''\ + Ast{kind}* {name}() const {{ return {retrieve}; }} + void add{Name}(Ast{kind}* nodep) {{ addNOp{n}p(reinterpret_cast(nodep)); }} + ''', + kind=kind, + name=name, + Name=name[0].upper() + name[1:], + n=n, + retrieve=retrieve) + elif monad == "Optional": + emitBlock('''\ + Ast{kind}* {name}() const {{ return {retrieve}; }} + void {name}(Ast{kind}* nodep) {{ setNOp{n}p(reinterpret_cast(nodep)); }} + ''', + kind=kind, + name=name, + n=n, + retrieve=retrieve) + else: + emitBlock('''\ + Ast{kind}* {name}() const {{ return {retrieve}; }} + void {name}(Ast{kind}* nodep) {{ setOp{n}p(reinterpret_cast(nodep)); }} + ''', + kind=kind, + name=name, + n=n, + retrieve=retrieve) + + fh.write( + " static_assert(true, \"\")\n") # Swallowing the semicolon + + # Only care about leaf classes for the rest + if node.isLeaf: + fh.write( + "#define ASTGEN_SUPER_{t}(...) Ast{b}(VNType::at{t}, __VA_ARGS__)\n" + .format(t=node.name, b=node.superClass.name)) + fh.write("\n") + + +def write_op_checks(filename): + with open_file(filename) as fh: + + indent = "" + + def emitBlock(pattern, **fmt): + fh.write( + textwrap.indent(textwrap.dedent(pattern), + indent).format(**fmt)) + + for node in SortedNodes: + if not node.isLeaf: + continue + + emitBlock('''\ + case VNType::at{nodeName}: {{ + const Ast{nodeName}* const currp = static_cast(this); + ''', + nodeName=node.name) + indent = " " + for n in range(1, 5): + op = node.getOp(n) + emitBlock("// Checking op{n}p\n", n=n) + if op: + name, monad, kind = op + if not monad: + emitBlock('''\ + UASSERT_OBJ(currp->{opName}(), currp, "Ast{nodeName} must have non nullptr {opName}()"); + UASSERT_OBJ(!currp->{opName}()->nextp(), currp, "Ast{nodeName}::{opName}() cannot have a non nullptr nextp()"); + currp->{opName}()->checkTreeIter(currp); + ''', + n=n, + nodeName=node.name, + opName=name) + elif monad == "Optional": + emitBlock('''\ + if (Ast{kind}* const opp = currp->{opName}()) {{ + UASSERT_OBJ(!currp->{opName}()->nextp(), currp, "Ast{nodeName}::{opName}() cannot have a non nullptr nextp()"); + opp->checkTreeIter(currp); + }} + ''', + n=n, + nodeName=node.name, + opName=name, + kind=kind) + elif monad == "List": + emitBlock('''\ + if (const Ast{kind}* const headp = currp->{opName}()) {{ + const AstNode* backp = currp; + const Ast{kind}* tailp = headp; + const Ast{kind}* opp = headp; + do {{ + opp->checkTreeIter(backp); + UASSERT_OBJ(opp == headp || !opp->nextp() || !opp->m_headtailp, opp, "Headtailp should be null in middle of lists"); + backp = tailp = opp; + opp = {next}; + }} while (opp); + UASSERT_OBJ(headp->m_headtailp == tailp, headp, "Tail in headtailp is inconsistent"); + UASSERT_OBJ(tailp->m_headtailp == headp, tailp, "Head in headtailp is inconsistent"); + }} + ''', + n=n, + nodeName=node.name, + opName=name, + kind=kind, + next="VN_AS(opp->nextp(), {kind})".format( + kind=kind) + if kind != "Node" else "opp->nextp()") + else: + sys.exit("Unknown operand type") + else: + emitBlock('''\ + UASSERT_OBJ(!currp->op{n}p(), currp, "Ast{nodeName} does not use op{n}p()"); + ''', + n=n, + nodeName=node.name) + indent = "" + emitBlock('''\ + break; + }} + ''') ###################################################################### @@ -662,6 +1005,9 @@ Version 2.0. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""") parser.add_argument('-I', action='store', help='source code include directory') +parser.add_argument('--astdef', + action='append', + help='add AST definition file (relative to -I)') parser.add_argument('--classes', action='store_true', help='makes class declaration files') @@ -671,21 +1017,61 @@ parser.add_argument('infiles', nargs='*', help='list of input .cpp filenames') Args = parser.parse_args() -read_types(Args.I + "/V3Ast.h") -read_types(Args.I + "/V3AstNodes.h") -for typen in sorted(Classes.keys()): +# Set up the root AstNode type. It is standalone so we don't need to parse the +# sources for this. +Nodes["Node"] = Node("Node", None, "AstNode", 1) + +# Read Ast node definitions +for filename in Args.astdef: + read_types(os.path.join(Args.I, filename)) + +# Compute derived properties over the whole AstNode hierarchy +Nodes["Node"].complete() + +SortedNodes = tuple(map(lambda _: Nodes[_], sorted(Nodes.keys()))) + +for node in SortedNodes: # Check all leaves are not AstNode* and non-leaves are AstNode* - children = children_of(typen) - if re.match(r'^Node', typen): - if len(children) == 0: + if re.match(r'^Node', node.name): + if node.isLeaf: sys.exit( "%Error: Final AstNode subclasses must not be named AstNode*: Ast" - + typen) + + node.name) else: - if len(children) != 0: + if not node.isLeaf: sys.exit( "%Error: Non-final AstNode subclasses must be named AstNode*: Ast" - + typen) + + node.name) + +# Check ordering of node definitions +files = tuple(sorted(set(_.file for _ in SortedNodes))) + +hasOrderingError = False +for file in files: + nodes = tuple(filter(lambda _, f=file: _.file == f, SortedNodes)) + expectOrder = tuple(sorted(nodes, key=lambda _: (_.isLeaf, _.ordIdx))) + actualOrder = tuple(sorted(nodes, key=lambda _: _.lineno)) + expect = { + node: pred + for pred, node in zip((None, ) + expectOrder[:-1], expectOrder) + } + actual = { + node: pred + for pred, node in zip((None, ) + actualOrder[:-1], actualOrder) + } + for node in nodes: + if expect[node] != actual[node]: + hasOrderingError = True + pred = expect[node] + print(file + ":" + str(node.lineno) + + ": %Error: Definition of 'Ast" + node.name + + "' is out of order. Should be " + + ("right after 'Ast" + pred.name + + "'" if pred else "first in file") + ".", + file=sys.stderr) + +if hasOrderingError: + sys.exit("%Error: Stopping due to out of order definitions listed above") read_stages(Args.I + "/Verilator.cpp") @@ -703,7 +1089,8 @@ if Args.classes: write_impl("V3Ast__gen_impl.h") write_types("V3Ast__gen_types.h") write_yystype("V3Ast__gen_yystype.h") - write_macros("V3AstNodes__gen_macros.h") + write_macros("V3Ast__gen_macros.h") + write_op_checks("V3Ast__gen_op_checks.h") for cpt in Args.infiles: if not re.search(r'.cpp$', cpt): diff --git a/src/bisonpre b/src/bisonpre index e03a7e41e..c60e3575d 100755 --- a/src/bisonpre +++ b/src/bisonpre @@ -391,9 +391,8 @@ def clean_input(filename, outname): if not re.match(r'^\s*$', line): sys.exit( "%Error: " + filename + ":" + str(lineno) + ": Need " + - needmore + - " more blank lines to keep line numbers are constant\n" - ) + str(needmore) + + " more blank lines to keep line numbers constant\n") needmore -= 1 else: lines.append(line) diff --git a/src/cppcheck_filtered b/src/cppcheck_filtered index 7e803b306..2b96dc070 100755 --- a/src/cppcheck_filtered +++ b/src/cppcheck_filtered @@ -117,7 +117,7 @@ def _suppress(filename, linenum, eid): if filename == "*": return False - # Cleanup for e.g. ../V3AstNodes.h + # Cleanup for e.g. ../V3AstNode*.h filename = re.sub(r'^\.\./(.*)', r'src/\1', filename) # Specific suppressions diff --git a/src/verilog.l b/src/verilog.l index c3eb40f4c..38adcdc84 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -24,8 +24,8 @@ // clang-format on #include "V3Number.h" -#include "V3ParseImp.h" // Defines YYTYPE; before including bison header #include "V3ParseBison.h" // Generated by bison +#include "V3ParseImp.h" // Defines YYTYPE; before including bison header #define STATE_VERILOG_RECENT S17 // State name for most recent Verilog Version @@ -325,8 +325,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "forever" { FL; return yFOREVER; } "fork" { FL; return yFORK; } "function" { FL; return yFUNCTION; } - "highz0" { FL; return ygenSTRENGTH; } - "highz1" { FL; return ygenSTRENGTH; } + "highz0" { FL; return yHIGHZ0; } + "highz1" { FL; return yHIGHZ1; } "if" { FL; return yIF; } "initial" { FL; return yINITIAL; } "inout" { FL; return yINOUT; } @@ -350,8 +350,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "pmos" { FL; return yPMOS; } "posedge" { FL; return yPOSEDGE; } "primitive" { FL; return yPRIMITIVE; } - "pull0" { FL; return ygenSTRENGTH; } - "pull1" { FL; return ygenSTRENGTH; } + "pull0" { FL; return yPULL0; } + "pull1" { FL; return yPULL1; } "pulldown" { FL; return yPULLDOWN; } "pullup" { FL; return yPULLUP; } "rcmos" { FL; return yRCMOS; } @@ -369,8 +369,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "small" { FL; return ygenSTRENGTH; } "specify" { FL; return ySPECIFY; } "specparam" { FL; return ySPECPARAM; } - "strong0" { FL; return ygenSTRENGTH; } - "strong1" { FL; return ygenSTRENGTH; } + "strong0" { FL; return ySTRONG0; } + "strong1" { FL; return ySTRONG1; } "supply0" { FL; return ySUPPLY0; } "supply1" { FL; return ySUPPLY1; } "table" { FL; yy_push_state(TABLE); return yTABLE; } @@ -388,8 +388,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "vectored" { FL; return yVECTORED; } "wait" { FL; return yWAIT; } "wand" { FL; return yWAND; } - "weak0" { FL; return ygenSTRENGTH; } - "weak1" { FL; return ygenSTRENGTH; } + "weak0" { FL; return yWEAK0; } + "weak1" { FL; return yWEAK1; } "while" { FL; return yWHILE; } "wire" { FL; return yWIRE; } "wor" { FL; return yWOR; } @@ -1004,7 +1004,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} return yaT_RESETALL; } // Rest handled by preproc "`suppress_faults" { FL_FWD; FL_BRK; } // Verilog-XL compatibility "`timescale"{ws}+[^\n\r]* { FL; PARSEP->lexTimescaleParse(yylval.fl, - yytext + strlen("`timescale")); + yytext + std::strlen("`timescale")); FL_BRK; } "`unconnected_drive"{ws}+"pull0" { FL; return yaT_UNCONNECTED_PULL0; } "`unconnected_drive"{ws}+"pull1" { FL; return yaT_UNCONNECTED_PULL1; } diff --git a/src/verilog.y b/src/verilog.y index 907ca05d2..674f2a3a2 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -23,12 +23,12 @@ #endif // clang-format on #include "V3Ast.h" -#include "V3Global.h" #include "V3Config.h" +#include "V3Global.h" #include "V3ParseImp.h" // Defines YYTYPE; before including bison header -#include #include +#include #include #define YYERROR_VERBOSE 1 // For prior to Bison 3.6 @@ -40,6 +40,13 @@ #define BBUNSUP(fl, msg) (fl)->v3warn(E_UNSUPPORTED, msg) #define GATEUNSUP(fl, tok) \ { BBUNSUP((fl), "Unsupported: Verilog 1995 gate primitive: " << (tok)); } +#define STRENGTHUNSUP(nodep) \ + { \ + if (nodep) { \ + BBUNSUP((nodep->fileline()), "Unsupported: Strength specifier on this gate type"); \ + nodep->deleteTree(); \ + } \ + } #define PRIMDLYUNSUP(nodep) \ { \ if (nodep) { \ @@ -68,6 +75,7 @@ public: AstNodeDType* m_varDTypep = nullptr; // Pointer to data type for next signal declaration AstNodeDType* m_memDTypep = nullptr; // Pointer to data type for next member declaration AstNode* m_netDelayp = nullptr; // Pointer to delay for next signal declaration + AstStrengthSpec* m_netStrengthp = nullptr; // Pointer to strength for next net declaration AstNodeModule* m_modp = nullptr; // Last module for timeunits bool m_pinAnsi = false; // In ANSI port list FileLine* m_instModuleFl = nullptr; // Fileline of module referenced for instantiations @@ -91,7 +99,7 @@ public: } // METHODS - AstNode* argWrapList(AstNode* nodep); + AstArg* argWrapList(AstNode* nodep); bool allTracingOn(FileLine* fl) { return v3Global.opt.trace() && m_tracingParse && fl->tracingOn(); } @@ -131,7 +139,7 @@ public: } AstDisplay* createDisplayError(FileLine* fileline) { AstDisplay* nodep = new AstDisplay(fileline, VDisplayType::DT_ERROR, "", nullptr, nullptr); - nodep->addNext(new AstStop(fileline, true)); + AstNode::addNext(nodep, new AstStop(fileline, true)); return nodep; } AstNode* createGatePin(AstNode* exprp) { @@ -172,6 +180,7 @@ public: m_varDTypep = dtypep; } void setNetDelay(AstNode* netDelayp) { m_netDelayp = netDelayp; } + void setNetStrength(AstStrengthSpec* netStrengthp) { m_netStrengthp = netStrengthp; } void pinPush() { m_pinStack.push(m_pinNum); m_pinNum = 1; @@ -291,6 +300,16 @@ int V3ParseGrammar::s_modTypeImpNum = 0; if (nodep) nodep->deleteTree(); \ } +#define APPLY_STRENGTH_TO_LIST(beginp, strengthSpecNodep, typeToCast) \ + { \ + if (AstStrengthSpec* specp = VN_CAST(strengthSpecNodep, StrengthSpec)) { \ + for (auto* nodep = beginp; nodep; nodep = nodep->nextp()) { \ + auto* const assignp = VN_AS(nodep, typeToCast); \ + assignp->strengthSpecp(nodep == beginp ? specp : specp->cloneTree(false)); \ + } \ + } \ + } + static void ERRSVKWD(FileLine* fileline, const string& tokname) { static int toldonce = 0; fileline->v3error( @@ -311,6 +330,12 @@ static void UNSUPREAL(FileLine* fileline) { void yyerror(const char* errmsg) { PARSEP->bisonLastFileline()->v3error(errmsg); } +template +static T_Node* addNextNull(T_Node* nodep, T_Next* nextp) { + if (!nextp) return nodep; + return AstNode::addNext(nodep, nextp); +} + //====================================================================== class AstSenTree; @@ -544,6 +569,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yGLOBAL__CLOCKING "global-then-clocking" %token yGLOBAL__ETC "global" %token yGLOBAL__LEX "global-in-lex" +%token yHIGHZ0 "highz0" +%token yHIGHZ1 "highz1" %token yIF "if" %token yIFF "iff" //UNSUP %token yIGNORE_BINS "ignore_bins" @@ -598,6 +625,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yPROGRAM "program" %token yPROPERTY "property" %token yPROTECTED "protected" +%token yPULL0 "pull0" +%token yPULL1 "pull1" %token yPULLDOWN "pulldown" %token yPULLUP "pullup" %token yPURE "pure" @@ -635,6 +664,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token ySTATIC__LEX "static-in-lex" %token ySTRING "string" //UNSUP %token ySTRONG "strong" +%token ySTRONG0 "strong0" +%token ySTRONG1 "strong1" %token ySTRUCT "struct" %token ySUPER "super" %token ySUPPLY0 "supply0" @@ -688,6 +719,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) //UNSUP %token yWAIT_ORDER "wait_order" %token yWAND "wand" //UNSUP %token yWEAK "weak" +%token yWEAK0 "weak0" +%token yWEAK1 "weak1" %token yWHILE "while" //UNSUP %token yWILDCARD "wildcard" %token yWIRE "wire" @@ -1035,6 +1068,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) // Blank lines for type insertion // Blank lines for type insertion // Blank lines for type insertion +// Blank lines for type insertion %start source_text @@ -1059,8 +1093,8 @@ description: // ==IEEE: description | interface_declaration { } | program_declaration { } | package_declaration { } - | package_item { if ($1) PARSEP->unitPackage($1->fileline())->addStmtp($1); } - | bind_directive { if ($1) PARSEP->unitPackage($1->fileline())->addStmtp($1); } + | package_item { if ($1) PARSEP->unitPackage($1->fileline())->addStmtsp($1); } + | bind_directive { if ($1) PARSEP->unitPackage($1->fileline())->addStmtsp($1); } // unsupported // IEEE: config_declaration // // Verilator only | yaT_RESETALL { } // Else, under design, and illegal based on IEEE 22.3 @@ -1086,7 +1120,7 @@ timeunits_declaration: // ==IEEE: timeunits_declaration package_declaration: // ==IEEE: package_declaration packageFront package_itemListE yENDPACKAGE endLabelE { $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); // Stash for implicit wires, etc - if ($2) $1->addStmtp($2); + if ($2) $1->addStmtsp($2); GRAMMARP->m_modp = nullptr; SYMP->popScope($1); GRAMMARP->endLabel($4,$1,$4); } @@ -1099,7 +1133,7 @@ packageFront: $$->lifetime($2); $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); $$->timeunit(PARSEP->timeLastUnit()); - PARSEP->rootp()->addModulep($$); + PARSEP->rootp()->addModulesp($$); SYMP->pushNew($$); GRAMMARP->m_modp = $$; } ; @@ -1111,7 +1145,7 @@ package_itemListE: // IEEE: [{ package_item }] package_itemList: // IEEE: { package_item } package_item { $$ = $1; } - | package_itemList package_item { $$ = $1->addNextNull($2); } + | package_itemList package_item { $$ = addNextNull($1, $2); } ; package_item: // ==IEEE: package_item @@ -1140,7 +1174,7 @@ package_or_generate_item_declaration: // ==IEEE: package_or_generate_i package_import_declarationList: package_import_declaration { $$ = $1; } - | package_import_declarationList package_import_declaration { $$ = $1->addNextNull($2); } + | package_import_declarationList package_import_declaration { $$ = addNextNull($1, $2); } ; package_import_declaration: // ==IEEE: package_import_declaration @@ -1149,7 +1183,7 @@ package_import_declaration: // ==IEEE: package_import_declaration package_import_itemList: package_import_item { $$ = $1; } - | package_import_itemList ',' package_import_item { $$ = $1->addNextNull($3); } + | package_import_itemList ',' package_import_item { $$ = addNextNull($1, $3); } ; package_import_item: // ==IEEE: package_import_item @@ -1177,7 +1211,7 @@ package_export_declaration: // IEEE: package_export_declaration package_export_itemList: package_export_item { $$ = $1; } - | package_export_itemList ',' package_export_item { $$ = $1->addNextNull($3); } + | package_export_itemList ',' package_export_item { $$ = addNextNull($1, $3); } ; package_export_item: // ==IEEE: package_export_item @@ -1195,18 +1229,18 @@ module_declaration: // ==IEEE: module_declaration modFront importsAndParametersE portsStarE ';' /*cont*/ module_itemListE yENDMODULE endLabelE { $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); // Stash for implicit wires, etc - if ($2) $1->addStmtp($2); - if ($3) $1->addStmtp($3); - if ($5) $1->addStmtp($5); + if ($2) $1->addStmtsp($2); + if ($3) $1->addStmtsp($3); + if ($5) $1->addStmtsp($5); GRAMMARP->m_modp = nullptr; SYMP->popScope($1); GRAMMARP->endLabel($7,$1,$7); } | udpFront parameter_port_listE portsStarE ';' /*cont*/ module_itemListE yENDPRIMITIVE endLabelE { $1->modTrace(false); // Stash for implicit wires, etc - if ($2) $1->addStmtp($2); - if ($3) $1->addStmtp($3); - if ($5) $1->addStmtp($5); + if ($2) $1->addStmtsp($2); + if ($3) $1->addStmtsp($3); + if ($5) $1->addStmtsp($5); GRAMMARP->m_tracingParse = true; GRAMMARP->m_modp = nullptr; SYMP->popScope($1); @@ -1226,7 +1260,7 @@ modFront: $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); $$->timeunit(PARSEP->timeLastUnit()); $$->unconnectedDrive(PARSEP->unconnectedDrive()); - PARSEP->rootp()->addModulep($$); + PARSEP->rootp()->addModulesp($$); SYMP->pushNew($$); GRAMMARP->m_modp = $$; } ; @@ -1234,7 +1268,7 @@ modFront: importsAndParametersE: // IEEE: common part of module_declaration, interface_declaration, program_declaration // // { package_import_declaration } [ parameter_port_list ] parameter_port_listE { $$ = $1; } - | package_import_declarationList parameter_port_listE { $$ = $1->addNextNull($2); } + | package_import_declarationList parameter_port_listE { $$ = addNextNull($1, $2); } ; udpFront: @@ -1242,9 +1276,9 @@ udpFront: { $$ = new AstPrimitive($3, *$3); $$->inLibrary(true); $$->lifetime($2); $$->modTrace(false); - $$->addStmtp(new AstPragma($3, VPragmaType::INLINE_MODULE)); + $$->addStmtsp(new AstPragma($3, VPragmaType::INLINE_MODULE)); GRAMMARP->m_tracingParse = false; - PARSEP->rootp()->addModulep($$); + PARSEP->rootp()->addModulesp($$); SYMP->pushNew($$); } ; @@ -1305,12 +1339,12 @@ portsStarE: // IEEE: .* + list_of_ports + list_of_port_decla list_of_portsE: // IEEE: list_of_ports + list_of_port_declarations portAndTagE { $$ = $1; } - | list_of_portsE ',' portAndTagE { $$ = $1->addNextNull($3); } + | list_of_portsE ',' portAndTagE { $$ = addNextNull($1, $3); } ; list_of_ports: // IEEE: list_of_ports + list_of_port_declarations portAndTag { $$ = $1; } - | list_of_portsE ',' portAndTagE { $$ = $1->addNextNull($3); } + | list_of_portsE ',' portAndTagE { $$ = addNextNull($1, $3); } ; portAndTagE: @@ -1348,11 +1382,11 @@ port: // ==IEEE: port portDirNetE id/*interface*/ portSig variable_dimensionListE sigAttrListE { $$ = $3; VARDECL(IFACEREF); VARIO(NONE); VARDTYPE(new AstIfaceRefDType($2,"",*$2)); - $$->addNextNull(VARDONEP($$,$4,$5)); } + addNextNull($$, VARDONEP($$,$4,$5)); } | portDirNetE id/*interface*/ '.' idAny/*modport*/ portSig variable_dimensionListE sigAttrListE { $$ = $5; VARDECL(IFACEREF); VARIO(NONE); VARDTYPE(new AstIfaceRefDType($2, $4, "", *$2, *$4)); - $$->addNextNull(VARDONEP($$,$6,$7)); } + addNextNull($$, VARDONEP($$,$6,$7)); } | portDirNetE yINTERFACE portSig rangeListE sigAttrListE { $$ = nullptr; BBUNSUP($2, "Unsupported: virtual or generic interfaces"); } | portDirNetE yINTERFACE '.' idAny/*modport*/ portSig rangeListE sigAttrListE @@ -1403,29 +1437,29 @@ port: // ==IEEE: port //UNSUP { UNSUP } // | portDirNetE data_type portSig variable_dimensionListE sigAttrListE - { $$=$3; VARDTYPE($2); $$->addNextNull(VARDONEP($$,$4,$5)); } + { $$=$3; VARDTYPE($2); addNextNull($$, VARDONEP($$,$4,$5)); } | portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE - { $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); } + { $$=$4; VARDTYPE($3); addNextNull($$, VARDONEP($$,$5,$6)); } | portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE - { $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); } + { $$=$4; VARDTYPE($3); addNextNull($$, VARDONEP($$,$5,$6)); } | portDirNetE signing portSig variable_dimensionListE sigAttrListE { $$=$3; VARDTYPE_NDECL(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2)); - $$->addNextNull(VARDONEP($$, $4, $5)); } + addNextNull($$, VARDONEP($$, $4, $5)); } | portDirNetE signingE rangeList portSig variable_dimensionListE sigAttrListE { $$=$4; VARDTYPE_NDECL(GRAMMARP->addRange( new AstBasicDType{$3->fileline(), LOGIC_IMPLICIT, $2}, $3, true)); - $$->addNextNull(VARDONEP($$, $5, $6)); } + addNextNull($$, VARDONEP($$, $5, $6)); } | portDirNetE /*implicit*/ portSig variable_dimensionListE sigAttrListE - { $$=$2; /*VARDTYPE-same*/ $$->addNextNull(VARDONEP($$,$3,$4)); } + { $$=$2; /*VARDTYPE-same*/ addNextNull($$, VARDONEP($$,$3,$4)); } // | portDirNetE data_type portSig variable_dimensionListE sigAttrListE '=' constExpr - { $$=$3; VARDTYPE($2); if (AstVar* vp = VARDONEP($$, $4, $5)) { $$->addNextNull(vp); vp->valuep($7); } } + { $$=$3; VARDTYPE($2); if (AstVar* vp = VARDONEP($$, $4, $5)) { addNextNull($$, vp); vp->valuep($7); } } | portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE '=' constExpr - { $$=$4; VARDTYPE($3); if (AstVar* vp = VARDONEP($$, $5, $6)) { $$->addNextNull(vp); vp->valuep($8); } } + { $$=$4; VARDTYPE($3); if (AstVar* vp = VARDONEP($$, $5, $6)) { addNextNull($$, vp); vp->valuep($8); } } | portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE '=' constExpr - { $$=$4; VARDTYPE($3); if (AstVar* vp = VARDONEP($$, $5, $6)) { $$->addNextNull(vp); vp->valuep($8); } } + { $$=$4; VARDTYPE($3); if (AstVar* vp = VARDONEP($$, $5, $6)) { addNextNull($$, vp); vp->valuep($8); } } | portDirNetE /*implicit*/ portSig variable_dimensionListE sigAttrListE '=' constExpr - { $$=$2; /*VARDTYPE-same*/ if (AstVar* vp = VARDONEP($$, $3, $4)) { $$->addNextNull(vp); vp->valuep($6); } } + { $$=$2; /*VARDTYPE-same*/ if (AstVar* vp = VARDONEP($$, $3, $4)) { addNextNull($$, vp); vp->valuep($6); } } ; portDirNetE: // IEEE: part of port, optional net type and/or direction @@ -1456,9 +1490,9 @@ interface_declaration: // IEEE: interface_declaration + interface_nonan // // timeunits_delcarationE is instead in interface_item intFront importsAndParametersE portsStarE ';' interface_itemListE yENDINTERFACE endLabelE - { if ($2) $1->addStmtp($2); - if ($3) $1->addStmtp($3); - if ($5) $1->addStmtp($5); + { if ($2) $1->addStmtsp($2); + if ($3) $1->addStmtsp($3); + if ($5) $1->addStmtsp($5); SYMP->popScope($1); } | yEXTERN intFront parameter_port_listE portsStarE ';' { BBUNSUP($1, "Unsupported: extern interface"); } @@ -1469,7 +1503,7 @@ intFront: { $$ = new AstIface($3, *$3); $$->inLibrary(true); $$->lifetime($2); - PARSEP->rootp()->addModulep($$); + PARSEP->rootp()->addModulesp($$); SYMP->pushNew($$); } ; @@ -1480,7 +1514,7 @@ interface_itemListE: interface_itemList: interface_item { $$ = $1; } - | interface_itemList interface_item { $$ = $1->addNextNull($2); } + | interface_itemList interface_item { $$ = addNextNull($1, $2); } ; interface_item: // IEEE: interface_item + non_port_interface_item @@ -1528,7 +1562,7 @@ anonymous_program_itemListE: // IEEE: { anonymous_program_item } anonymous_program_itemList: // IEEE: { anonymous_program_item } anonymous_program_item { $$ = $1; } - | anonymous_program_itemList anonymous_program_item { $$ = $1->addNextNull($2); } + | anonymous_program_itemList anonymous_program_item { $$ = addNextNull($1, $2); } ; anonymous_program_item: // ==IEEE: anonymous_program_item @@ -1545,9 +1579,9 @@ program_declaration: // IEEE: program_declaration + program_nonansi_h pgmFront parameter_port_listE portsStarE ';' /*cont*/ program_itemListE yENDPROGRAM endLabelE { $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); // Stash for implicit wires, etc - if ($2) $1->addStmtp($2); - if ($3) $1->addStmtp($3); - if ($5) $1->addStmtp($5); + if ($2) $1->addStmtsp($2); + if ($3) $1->addStmtsp($3); + if ($5) $1->addStmtsp($5); GRAMMARP->m_modp = nullptr; SYMP->popScope($1); GRAMMARP->endLabel($7,$1,$7); } @@ -1563,7 +1597,7 @@ pgmFront: $$->inLibrary(PARSEP->inLibrary() || $$->fileline()->celldefineOn()); $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); $$->timeunit(PARSEP->timeLastUnit()); - PARSEP->rootp()->addModulep($$); + PARSEP->rootp()->addModulesp($$); SYMP->pushNew($$); GRAMMARP->m_modp = $$; } ; @@ -1575,7 +1609,7 @@ program_itemListE: // ==IEEE: [{ program_item }] program_itemList: // ==IEEE: { program_item } program_item { $$ = $1; } - | program_itemList program_item { $$ = $1->addNextNull($2); } + | program_itemList program_item { $$ = addNextNull($1, $2); } ; program_item: // ==IEEE: program_item @@ -1615,7 +1649,7 @@ modport_declaration: // ==IEEE: modport_declaration modport_itemList: // IEEE: part of modport_declaration modport_item { $$ = $1; } - | modport_itemList ',' modport_item { $$ = $1->addNextNull($3); } + | modport_itemList ',' modport_item { $$ = addNextNull($1, $3); } ; modport_item: // ==IEEE: modport_item @@ -1626,7 +1660,7 @@ modport_item: // ==IEEE: modport_item modportPortsDeclList: modportPortsDecl { $$ = $1; } - | modportPortsDeclList ',' modportPortsDecl { $$ = $1->addNextNull($3); } + | modportPortsDeclList ',' modportPortsDecl { $$ = addNextNull($1, $3); } ; // IEEE: modport_ports_declaration + modport_simple_ports_declaration @@ -1718,11 +1752,18 @@ parameter_port_declarationTypeFrontE: // IEEE: parameter_port_declaration w/o as ; net_declaration: // IEEE: net_declaration - excluding implict - net_declarationFront netSigList ';' { $$ = $2; } + net_declarationFront netSigList ';' + { $$ = $2; + if (GRAMMARP->m_netStrengthp) { + VL_DO_CLEAR(delete GRAMMARP->m_netStrengthp, GRAMMARP->m_netStrengthp = nullptr); + }} ; net_declarationFront: // IEEE: beginning of net_declaration - net_declRESET net_type strengthSpecE net_scalaredE net_dataTypeE { VARDTYPE_NDECL($5); } + net_declRESET net_type driveStrengthE net_scalaredE net_dataTypeE + { VARDTYPE_NDECL($5); + GRAMMARP->setNetStrength(VN_CAST($3, StrengthSpec)); + } //UNSUP net_declRESET yINTERCONNECT signingE rangeListE { VARNET($2); VARDTYPE(x); } ; @@ -1968,12 +2009,13 @@ struct_unionDecl: // IEEE: part of data_type { $$ = $5; $$->addMembersp($6); SYMP->popScope($$); } ; -struct_union_memberList: // IEEE: { struct_union_member } +struct_union_memberList: // IEEE: { struct_union_member } struct_union_member { $$ = $1; } - | struct_union_memberList struct_union_member { $$ = $1->addNextNull($2); } + + | struct_union_memberList struct_union_member { $$ = addNextNull($1, $2); } ; -struct_union_member: // ==IEEE: struct_union_member +struct_union_member: // ==IEEE: struct_union_member // // UNSUP random_qualifer not propagagted until have randomize support random_qualifierE data_type_or_void /*mid*/ { GRAMMARP->m_memDTypep = $2; } // As a list follows, need to attach this dtype to each member. @@ -1981,9 +2023,9 @@ struct_union_member: // ==IEEE: struct_union_member | vlTag { $$ = nullptr; } ; -list_of_member_decl_assignments: // Derived from IEEE: list_of_variable_decl_assignments +list_of_member_decl_assignments: // Derived from IEEE: list_of_variable_decl_assignments member_decl_assignment { $$ = $1; } - | list_of_member_decl_assignments ',' member_decl_assignment { $$ = $1->addNextNull($3); } + | list_of_member_decl_assignments ',' member_decl_assignment { $$ = addNextNull($1, $3); } ; member_decl_assignment: // Derived from IEEE: variable_decl_assignment @@ -2016,7 +2058,7 @@ member_decl_assignment: // Derived from IEEE: variable_decl_assi list_of_variable_decl_assignments: // ==IEEE: list_of_variable_decl_assignments variable_decl_assignment { $$ = $1; } - | list_of_variable_decl_assignments ',' variable_decl_assignment { $$ = VN_CAST($1->addNextNull($3), Var); } + | list_of_variable_decl_assignments ',' variable_decl_assignment { $$ = addNextNull($1, $3); } ; variable_decl_assignment: // ==IEEE: variable_decl_assignment @@ -2046,7 +2088,7 @@ list_of_tf_variable_identifiers: // ==IEEE: list_of_tf_variable_identifie tf_variable_identifier: // IEEE: part of list_of_tf_variable_identifiers id variable_dimensionListE sigAttrListE exprEqE { $$ = VARDONEA($1,*$1, $2, $3); - if ($4) $$->addNext(new AstAssign($4->fileline(), new AstVarRef($1, *$1, VAccess::WRITE), $4)); } + if ($4) AstNode::addNext($$, new AstAssign($4->fileline(), new AstVarRef($1, *$1, VAccess::WRITE), $4)); } ; variable_declExpr: // IEEE: part of variable_decl_assignment - rhs of expr @@ -2062,7 +2104,7 @@ variable_dimensionListE: // IEEE: variable_dimension + empty variable_dimensionList: // IEEE: variable_dimension + empty variable_dimension { $$ = $1; } - | variable_dimensionList variable_dimension { $$ = VN_CAST($1->addNext($2), NodeRange); } + | variable_dimensionList variable_dimension { $$ = $1->addNext($2); } ; variable_dimension: // ==IEEE: variable_dimension @@ -2137,17 +2179,17 @@ enum_base_typeE: // IEEE: enum_base_type $$ = GRAMMARP->createArray(refp, $3, true); } ; -enum_nameList: +enum_nameList: enum_name_declaration { $$ = $1; } - | enum_nameList ',' enum_name_declaration { $$ = $1->addNextNull($3); } + | enum_nameList ',' enum_name_declaration { $$ = addNextNull($1, $3); } ; -enum_name_declaration: // ==IEEE: enum_name_declaration +enum_name_declaration: // ==IEEE: enum_name_declaration idAny/*enum_identifier*/ enumNameRangeE enumNameStartE { $$ = new AstEnumItem($1, *$1, $2, $3); } ; -enumNameRangeE: // IEEE: second part of enum_name_declaration +enumNameRangeE: // IEEE: second part of enum_name_declaration /* empty */ { $$ = nullptr; } | '[' intnumAsConst ']' @@ -2330,7 +2372,7 @@ dtypeAttrListE: dtypeAttrList: dtypeAttr { $$ = $1; } - | dtypeAttrList dtypeAttr { $$ = $1->addNextNull($2); } + | dtypeAttrList dtypeAttr { $$ = addNextNull($1, $2); } ; dtypeAttr: @@ -2351,7 +2393,7 @@ module_itemListE: // IEEE: Part of module_declaration module_itemList: // IEEE: Part of module_declaration module_item { $$ = $1; } - | module_itemList module_item { $$ = $1->addNextNull($2); } + | module_itemList module_item { $$ = addNextNull($1, $2); } ; module_item: // ==IEEE: module_item @@ -2425,13 +2467,14 @@ module_common_item: // ==IEEE: module_common_item ; continuous_assign: // IEEE: continuous_assign - yASSIGN strengthSpecE delayE assignList ';' + yASSIGN driveStrengthE delayE assignList ';' { $$ = $4; + APPLY_STRENGTH_TO_LIST($$, $2, AssignW); if ($3) for (auto* nodep = $$; nodep; nodep = nodep->nextp()) { auto* const assignp = VN_AS(nodep, NodeAssign); - assignp->addTimingControlp(nodep == $$ ? $3 : $3->cloneTree(false)); + assignp->timingControlp(nodep == $$ ? $3 : $3->cloneTree(false)); } } ; @@ -2538,7 +2581,7 @@ genItemOrBegin: // Not in IEEE, but our begin isn't under genera genItemList: ~c~genItemOrBegin { $$ = $1; } - | ~c~genItemList ~c~genItemOrBegin { $$ = $1->addNextNull($2); } + | ~c~genItemList ~c~genItemOrBegin { $$ = addNextNull($1, $2); } ; //UNSUPc_genItemList: // (for checkers) @@ -2593,7 +2636,7 @@ loop_generate_construct: // ==IEEE: loop_generate_construct } // Statements are under 'genforp' as cells under this // for loop won't get an extra layer of hierarchy tacked on - blkp->addGenforp(new AstGenFor($1, initp, $5, $7, lowerNoBegp)); + blkp->genforp(new AstGenFor($1, initp, $5, $7, lowerNoBegp)); $$ = blkp; VL_DO_DANGLING(lowerBegp->deleteTree(), lowerBegp); } @@ -2606,7 +2649,7 @@ loop_generate_construct: // ==IEEE: loop_generate_construct genvar_initialization: // ==IEEE: genvar_initialization varRefBase '=' expr { $$ = new AstAssign($2,$1,$3); } | yGENVAR genvar_identifierDecl '=' constExpr - { $$ = $2; $2->addNext(new AstAssign($3, new AstVarRef($2->fileline(), $2, VAccess::WRITE), $4)); } + { $$ = $2; AstNode::addNext($$, new AstAssign($3, new AstVarRef($2->fileline(), $2, VAccess::WRITE), $4)); } ; genvar_iteration: // ==IEEE: genvar_iteration @@ -2638,12 +2681,12 @@ genvar_iteration: // ==IEEE: genvar_iteration new AstConst{$2, AstConst::StringToParse{}, "'b1"}}}; } ; -case_generate_itemListE: // IEEE: [{ case_generate_itemList }] +case_generate_itemListE: // IEEE: [{ case_generate_itemList }] /* empty */ { $$ = nullptr; } | case_generate_itemList { $$ = $1; } ; -case_generate_itemList: // IEEE: { case_generate_itemList } +case_generate_itemList: // IEEE: { case_generate_itemList } ~c~case_generate_item { $$ = $1; } | ~c~case_generate_itemList ~c~case_generate_item { $$ = $1; $1->addNext($2); } ; @@ -2652,7 +2695,7 @@ case_generate_itemList: // IEEE: { case_generate_itemList } //UNSUP BISONPRE_COPY(case_generate_itemList,{s/~c~/c_/g}) // {copied} //UNSUP ; -case_generate_item: // ==IEEE: case_generate_item +case_generate_item: // ==IEEE: case_generate_item caseCondList colon generate_block_or_null { $$ = new AstCaseItem{$2, $1, $3}; } | yDEFAULT colon generate_block_or_null { $$ = new AstCaseItem{$1, nullptr, $3}; } | yDEFAULT generate_block_or_null { $$ = new AstCaseItem{$1, nullptr, $2}; } @@ -2726,8 +2769,9 @@ netSig: // IEEE: net_decl_assignment - one element from | netId sigAttrListE '=' expr { $$ = VARDONEA($1, *$1, nullptr, $2); auto* const assignp = new AstAssignW{$3, new AstVarRef{$1, *$1, VAccess::WRITE}, $4}; - if ($$->delayp()) assignp->addTimingControlp($$->delayp()->unlinkFrBack()); // IEEE 1800-2017 10.3.3 - $$->addNext(assignp); } | netId variable_dimensionList sigAttrListE + if (GRAMMARP->m_netStrengthp) assignp->strengthSpecp(GRAMMARP->m_netStrengthp->cloneTree(false)); + if ($$->delayp()) assignp->timingControlp($$->delayp()->unlinkFrBack()); // IEEE 1800-2017 10.3.3 + AstNode::addNext($$, assignp); } | netId variable_dimensionList sigAttrListE { $$ = VARDONEA($1,*$1, $2, $3); } ; @@ -2743,7 +2787,7 @@ sigAttrListE: sigAttrList: sigAttr { $$ = $1; } - | sigAttrList sigAttr { $$ = $1->addNextNull($2); } + | sigAttrList sigAttr { $$ = addNextNull($1, $2); } ; sigAttr: @@ -2770,7 +2814,7 @@ rangeListE: // IEEE: [{packed_dimension}] rangeList: // IEEE: {packed_dimension} anyrange { $$ = $1; } - | rangeList anyrange { $$ = $1; $1->addNext($2); } + | rangeList anyrange { $$ = $1->addNext($2); } ; //UNSUPbit_selectE: // IEEE: constant_bit_select (IEEE included empty) @@ -2792,7 +2836,7 @@ packed_dimensionListE: // IEEE: [{ packed_dimension }] packed_dimensionList: // IEEE: { packed_dimension } packed_dimension { $$ = $1; } - | packed_dimensionList packed_dimension { $$ = VN_CAST($1->addNext($2), NodeRange); } + | packed_dimensionList packed_dimension { $$ = $1->addNext($2); } ; packed_dimension: // ==IEEE: packed_dimension @@ -2821,7 +2865,7 @@ param_assignment: // ==IEEE: param_assignment list_of_param_assignments: // ==IEEE: list_of_param_assignments param_assignment { $$ = $1; } - | list_of_param_assignments ',' param_assignment { $$ = $1; $1->addNext($3); } + | list_of_param_assignments ',' param_assignment { $$ = $1->addNext($3); } ; type_assignment: // ==IEEE: type_assignment @@ -2832,7 +2876,7 @@ type_assignment: // ==IEEE: type_assignment list_of_type_assignments: // ==IEEE: list_of_type_assignments type_assignment { $$ = $1; } - | list_of_type_assignments ',' type_assignment { $$ = $1; $1->addNext($3); } + | list_of_type_assignments ',' type_assignment { $$ = $1->addNext($3); } ; list_of_defparam_assignments: //== IEEE: list_of_defparam_assignments @@ -2912,7 +2956,7 @@ instRangeListE: instRangeList: instRange { $$ = $1; } - | instRangeList instRange { $$ = VN_CAST($1->addNextNull($2), Range); } + | instRangeList instRange { $$ = addNextNull($1, $2); } ; instRange: @@ -2932,12 +2976,12 @@ cellpinList: cellparamItList: // IEEE: list_of_parameter_assignmente cellparamItemE { $$ = $1; } - | cellparamItList ',' cellparamItemE { $$ = VN_CAST($1->addNextNull($3), Pin); } + | cellparamItList ',' cellparamItemE { $$ = addNextNull($1, $3); } ; cellpinItList: // IEEE: list_of_port_connections cellpinItemE { $$ = $1; } - | cellpinItList ',' cellpinItemE { $$ = VN_CAST($1->addNextNull($3), Pin); } + | cellpinItList ',' cellpinItemE { $$ = addNextNull($1, $3); } ; cellparamItemE: // IEEE: named_parameter_assignment + empty @@ -3015,11 +3059,11 @@ event_control: // ==IEEE: event_control event_expression: // IEEE: event_expression - split over several //UNSUP // Below are all removed senitem { $$ = $1; } - | event_expression yOR senitem { $$ = VN_CAST($1->addNextNull($3), SenItem); } - | event_expression ',' senitem { $$ = VN_CAST($1->addNextNull($3), SenItem); } /* Verilog 2001 */ + | event_expression yOR senitem { $$ = addNextNull($1, $3); } + | event_expression ',' senitem { $$ = addNextNull($1, $3); } /* Verilog 2001 */ //UNSUP // Above are all removed, replace with: //UNSUP ev_expr { $$ = $1; } - //UNSUP event_expression ',' ev_expr %prec yOR { $$ = VN_CAST($1->addNextNull($3), SenItem); } + //UNSUP event_expression ',' ev_expr %prec yOR { $$ = addNextNull($1, $3); } ; senitem: // IEEE: part of event_expression, non-'OR' ',' terms @@ -3131,7 +3175,7 @@ par_blockFrontPreId: // IEEE: part of par_block/stmt with leading id blockDeclStmtList: // IEEE: { block_item_declaration } { statement or null } // // The spec seems to suggest a empty declaration isn't ok, but most simulators take it block_item_declarationList { $$ = $1; } - | block_item_declarationList stmtList { $$ = $1->addNextNull($2); } + | block_item_declarationList stmtList { $$ = addNextNull($1, $2); } | stmtList { $$ = $1; } ; @@ -3142,7 +3186,7 @@ blockDeclStmtListE: // IEEE: [ { block_item_declaration } { statemen block_item_declarationList: // IEEE: [ block_item_declaration ] block_item_declaration { $$ = $1; } - | block_item_declarationList block_item_declaration { $$ = $1->addNextNull($2); } + | block_item_declarationList block_item_declaration { $$ = addNextNull($1, $2); } ; block_item_declaration: // ==IEEE: block_item_declaration @@ -3153,7 +3197,7 @@ block_item_declaration: // ==IEEE: block_item_declaration stmtList: stmtBlock { $$ = $1; } - | stmtList stmtBlock { $$ = $2 ? $1->addNext($2) : $1; } + | stmtList stmtBlock { $$ = addNextNull($1, $2); } ; stmt: // IEEE: statement_or_null == function_statement_or_null @@ -3452,23 +3496,23 @@ case_itemList: // IEEE: { case_item + ... } caseCondList colon stmtBlock { $$ = new AstCaseItem{$2, $1, $3}; } | yDEFAULT colon stmtBlock { $$ = new AstCaseItem{$1, nullptr, $3}; } | yDEFAULT stmtBlock { $$ = new AstCaseItem{$1, nullptr, $2}; } - | case_itemList caseCondList colon stmtBlock { $$ = $1; $1->addNext(new AstCaseItem{$3, $2, $4}); } - | case_itemList yDEFAULT stmtBlock { $$ = $1; $1->addNext(new AstCaseItem{$2, nullptr, $3}); } - | case_itemList yDEFAULT colon stmtBlock { $$ = $1; $1->addNext(new AstCaseItem{$2, nullptr, $4}); } + | case_itemList caseCondList colon stmtBlock { $$ = $1->addNext(new AstCaseItem{$3, $2, $4}); } + | case_itemList yDEFAULT stmtBlock { $$ = $1->addNext(new AstCaseItem{$2, nullptr, $3}); } + | case_itemList yDEFAULT colon stmtBlock { $$ = $1->addNext(new AstCaseItem{$2, nullptr, $4}); } ; case_inside_itemList: // IEEE: { case_inside_item + open_range_list ... } open_range_list colon stmtBlock { $$ = new AstCaseItem{$2, $1, $3}; } | yDEFAULT colon stmtBlock { $$ = new AstCaseItem{$1, nullptr, $3}; } | yDEFAULT stmtBlock { $$ = new AstCaseItem{$1, nullptr, $2}; } - | case_inside_itemList open_range_list colon stmtBlock { $$ = $1; $1->addNext(new AstCaseItem{$3, $2, $4}); } - | case_inside_itemList yDEFAULT stmtBlock { $$ = $1; $1->addNext(new AstCaseItem{$2, nullptr, $3}); } - | case_inside_itemList yDEFAULT colon stmtBlock { $$ = $1; $1->addNext(new AstCaseItem{$2, nullptr, $4}); } + | case_inside_itemList open_range_list colon stmtBlock { $$ = $1->addNext(new AstCaseItem{$3, $2, $4}); } + | case_inside_itemList yDEFAULT stmtBlock { $$ = $1->addNext(new AstCaseItem{$2, nullptr, $3}); } + | case_inside_itemList yDEFAULT colon stmtBlock { $$ = $1->addNext(new AstCaseItem{$2, nullptr, $4}); } ; open_range_list: // ==IEEE: open_range_list + open_value_range open_value_range { $$ = $1; } - | open_range_list ',' open_value_range { $$ = $1; $1->addNext($3); } + | open_range_list ',' open_value_range { $$ = $1->addNext($3); } ; open_value_range: // ==IEEE: open_value_range @@ -3487,7 +3531,7 @@ value_range: // ==IEEE: value_range caseCondList: // IEEE: part of case_item expr { $$ = $1; } - | caseCondList ',' expr { $$ = $1; $1->addNext($3); } + | caseCondList ',' expr { $$ = $1->addNext($3); } ; patternNoExpr: // IEEE: pattern **Excluding Expr* @@ -3504,7 +3548,7 @@ patternNoExpr: // IEEE: pattern **Excluding Expr* patternList: // IEEE: part of pattern patternOne { $$ = $1; } - | patternList ',' patternOne { $$ = $1->addNextNull($3); } + | patternList ',' patternOne { $$ = addNextNull($1, $3); } ; patternOne: // IEEE: part of pattern @@ -3516,7 +3560,7 @@ patternOne: // IEEE: part of pattern patternMemberList: // IEEE: part of pattern and assignment_pattern patternMemberOne { $$ = $1; } - | patternMemberList ',' patternMemberOne { $$ = $1->addNextNull($3); } + | patternMemberList ',' patternMemberOne { $$ = addNextNull($1, $3); } ; patternMemberOne: // IEEE: part of pattern and assignment_pattern @@ -3598,7 +3642,7 @@ for_stepE: // IEEE: for_step + empty for_step: // IEEE: for_step for_step_assignment { $$ = $1; } - | for_step ',' for_step_assignment { $$ = AstNode::addNextNull($1, $3); } + | for_step ',' for_step_assignment { $$ = addNextNull($1, $3); } ; for_step_assignment: // ==IEEE: for_step_assignment @@ -3617,7 +3661,7 @@ for_step_assignment: // ==IEEE: for_step_assignment loop_variables: // IEEE: loop_variables parseRefBase { $$ = $1; } - | loop_variables ',' parseRefBase { $$ = $1; $$->addNext($3); } + | loop_variables ',' parseRefBase { $$ = $1->addNext($3); } | ',' parseRefBase { $$ = new AstEmpty{$1}; $$->addNext($2); } ; @@ -3891,7 +3935,7 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task or | yD_POW '(' expr ',' expr ')' { $$ = new AstPowD($1,$3,$5); } | yD_RANDOM '(' expr ')' { $$ = new AstRand($1, $3, false); } | yD_RANDOM parenE { $$ = new AstRand($1, nullptr, false); } - | yD_REALTIME parenE { $$ = new AstTimeD($1, VTimescale(VTimescale::NONE)); } + | yD_REALTIME parenE { $$ = new AstTimeD{$1, VTimescale{VTimescale::NONE}}; } | yD_REALTOBITS '(' expr ')' { $$ = new AstRealToBits($1,$3); } | yD_REWIND '(' idClassSel ')' { $$ = new AstFSeek($1, $3, new AstConst($1, 0), new AstConst($1, 0)); } | yD_RIGHT '(' exprOrDataType ')' { $$ = new AstAttrOf($1,VAttrType::DIM_RIGHT,$3,nullptr); } @@ -3909,13 +3953,14 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task or | yD_SIZE '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,VAttrType::DIM_SIZE,$3,$5); } | yD_SQRT '(' expr ')' { $$ = new AstSqrtD($1,$3); } | yD_SSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstSScanF($1,*$5,$3,$6); } - | yD_STIME parenE { $$ = new AstSel($1, new AstTime($1, VTimescale(VTimescale::NONE)), 0, 32); } + | yD_STIME parenE + { $$ = new AstSel{$1, new AstTime{$1, VTimescale{VTimescale::NONE}}, 0, 32}; } | yD_STABLE '(' expr ')' { $$ = new AstStable($1,$3); } | yD_STABLE '(' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $stable and clock arguments"); } | yD_TAN '(' expr ')' { $$ = new AstTanD($1,$3); } | yD_TANH '(' expr ')' { $$ = new AstTanhD($1,$3); } | yD_TESTPLUSARGS '(' expr ')' { $$ = new AstTestPlusArgs($1, $3); } - | yD_TIME parenE { $$ = new AstTime($1, VTimescale(VTimescale::NONE)); } + | yD_TIME parenE { $$ = new AstTime{$1, VTimescale{VTimescale::NONE}}; } | yD_TYPENAME '(' exprOrDataType ')' { $$ = new AstAttrOf($1, VAttrType::TYPENAME, $3); } | yD_UNGETC '(' expr ',' expr ')' { $$ = new AstFUngetC($1, $5, $3); } // Arg swap to file first | yD_UNPACKED_DIMENSIONS '(' exprOrDataType ')' { $$ = new AstAttrOf($1,VAttrType::DIM_UNPK_DIMENSIONS,$3); } @@ -3972,7 +4017,7 @@ exprOrDataType: // expr | data_type: combined to prevent conflic //UNSUPexprOrDataTypeList: //UNSUP exprOrDataType { $$ = $1; } -//UNSUP | exprOrDataTypeList ',' exprOrDataType { $$ = AstNode::addNextNull($1, $3); } +//UNSUP | exprOrDataTypeList ',' exprOrDataType { $$ = addNextNull($1, $3); } //UNSUP ; list_of_argumentsE: // IEEE: [list_of_arguments] @@ -3981,7 +4026,7 @@ list_of_argumentsE: // IEEE: [list_of_arguments] { if (VN_IS($1, Arg) && VN_CAST($1, Arg)->emptyConnectNoNext()) { $1->deleteTree(); $$ = nullptr; // Mis-created when have 'func()' } else { $$ = $1; } } - | argsExprListE ',' argsDottedList { $$ = $1->addNextNull($3); } + | argsExprListE ',' argsDottedList { $$ = addNextNull($1, $3); } ; task_declaration: // ==IEEE: task_declaration @@ -4067,19 +4112,19 @@ funcId: // IEEE: function_data_type_or_implicit // // function_data_type expanded here to prevent conflicts with implicit_type:empty vs data_type:ID /**/ fIdScoped { $$ = $1; - $$->addFvarp(new AstBasicDType($1, LOGIC_IMPLICIT)); + $$->fvarp(new AstBasicDType($1, LOGIC_IMPLICIT)); SYMP->pushNewUnderNodeOrCurrent($$, $1); } | signingE rangeList fIdScoped { $$ = $3; - $$->addFvarp(GRAMMARP->addRange(new AstBasicDType($3, LOGIC_IMPLICIT, $1), $2,true)); + $$->fvarp(GRAMMARP->addRange(new AstBasicDType($3, LOGIC_IMPLICIT, $1), $2,true)); SYMP->pushNewUnderNodeOrCurrent($$, $3); } | signing fIdScoped { $$ = $2; - $$->addFvarp(new AstBasicDType($2, LOGIC_IMPLICIT, $1)); + $$->fvarp(new AstBasicDType($2, LOGIC_IMPLICIT, $1)); SYMP->pushNewUnderNodeOrCurrent($$, $2); } | data_type fIdScoped { $$ = $2; - $$->addFvarp($1); + $$->fvarp($1); SYMP->pushNewUnderNodeOrCurrent($$, $2); } // // To verilator tasks are the same as void functions (we separately detect time passing) | yVOID taskId @@ -4123,20 +4168,20 @@ fIdScoped: // IEEE: part of function_body_declaration/task_ ; tfGuts: - '(' tf_port_listE ')' ';' tfBodyE { $$ = $2->addNextNull($5); } + '(' tf_port_listE ')' ';' tfBodyE { $$ = addNextNull($2, $5); } | ';' tfBodyE { $$ = $2; } ; tfBodyE: // IEEE: part of function_body_declaration/task_body_declaration /* empty */ { $$ = nullptr; } | tf_item_declarationList { $$ = $1; } - | tf_item_declarationList stmtList { $$ = $1->addNextNull($2); } + | tf_item_declarationList stmtList { $$ = addNextNull($1, $2); } | stmtList { $$ = $1; } ; tf_item_declarationList: tf_item_declaration { $$ = $1; } - | tf_item_declarationList tf_item_declaration { $$ = $1->addNextNull($2); } + | tf_item_declarationList tf_item_declaration { $$ = addNextNull($1, $2); } ; tf_item_declaration: // ==IEEE: tf_item_declaration @@ -4159,7 +4204,7 @@ tf_port_listE: // IEEE: tf_port_list + empty tf_port_listList: // IEEE: part of tf_port_list tf_port_item { $$ = $1; } - | tf_port_listList ',' tf_port_item { $$ = $1->addNextNull($3); } + | tf_port_listList ',' tf_port_item { $$ = addNextNull($1, $3); } ; tf_port_item: // ==IEEE: tf_port_item @@ -4592,7 +4637,7 @@ exprStrText: cStrList: exprStrText { $$ = $1; } - | exprStrText ',' cStrList { $$ = $1; $1->addNext($3); } + | exprStrText ',' cStrList { $$ = $1->addNext($3); } ; cateList: @@ -4608,20 +4653,20 @@ exprListE: exprList: expr { $$ = $1; } - | exprList ',' expr { $$ = $1; $1->addNext($3); } + | exprList ',' expr { $$ = $1->addNext($3); } ; exprDispList: // exprList for within $display expr { $$ = $1; } - | exprDispList ',' expr { $$ = $1; $1->addNext($3); } + | exprDispList ',' expr { $$ = $1->addNext($3); } // // ,, creates a space in $display | exprDispList ',' /*empty*/ - { $$ = $1; $1->addNext(new AstConst($2, AstConst::VerilogStringLiteral(), " ")); } + { $$ = $1->addNext(new AstConst($2, AstConst::VerilogStringLiteral(), " ")); } ; vrdList: idClassSel { $$ = $1; } - | vrdList ',' idClassSel { $$ = $1; $1->addNext($3); } + | vrdList ',' idClassSel { $$ = $1->addNext($3); } ; commaVRDListE: @@ -4641,7 +4686,7 @@ argsExprListE: // IEEE: part of list_of_arguments //UNSUPpev_argsExprListE: // IEEE: part of list_of_arguments - pev_expr at bottom //UNSUP pev_argsExprOneE { $$ = $1; } -//UNSUP | pev_argsExprListE ',' pev_argsExprOneE { $$ = AstNode::addNextNull($1, $3); } +//UNSUP | pev_argsExprListE ',' pev_argsExprOneE { $$ = addNextNull($1, $3); } //UNSUP ; argsExprOneE: // IEEE: part of list_of_arguments @@ -4656,12 +4701,12 @@ argsExprOneE: // IEEE: part of list_of_arguments argsDottedList: // IEEE: part of list_of_arguments argsDotted { $$ = $1; } - | argsDottedList ',' argsDotted { $$ = $1->addNextNull($3); } + | argsDottedList ',' argsDotted { $$ = addNextNull($1, $3); } ; //UNSUPpev_argsDottedList: // IEEE: part of list_of_arguments - pev_expr at bottom //UNSUP pev_argsDotted { $$ = $1; } -//UNSUP | pev_argsDottedList ',' pev_argsDotted { $$ = AstNode::addNextNull($1, $3); } +//UNSUP | pev_argsDottedList ',' pev_argsDotted { $$ = addNextNull($1, $3); } //UNSUP ; argsDotted: // IEEE: part of list_of_arguments @@ -4718,18 +4763,30 @@ stream_expressionOrDataType: // IEEE: from streaming_concatenation // Gate declarations gateDecl: - yBUF delayE gateBufList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yBUFIF0 delayE gateBufif0List ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yBUFIF1 delayE gateBufif1List ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yNOT delayE gateNotList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yNOTIF0 delayE gateNotif0List ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yNOTIF1 delayE gateNotif1List ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yAND delayE gateAndList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yNAND delayE gateNandList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yOR delayE gateOrList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yNOR delayE gateNorList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yXOR delayE gateXorList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yXNOR delayE gateXnorList ';' { $$ = $3; PRIMDLYUNSUP($2); } + yBUF driveStrengthE delayE gateBufList ';' + { $$ = $4; STRENGTHUNSUP($2); PRIMDLYUNSUP($3); } + | yBUFIF0 driveStrengthE delayE gateBufif0List ';' + { $$ = $4; STRENGTHUNSUP($2); PRIMDLYUNSUP($3); } + | yBUFIF1 driveStrengthE delayE gateBufif1List ';' + { $$ = $4; STRENGTHUNSUP($2); PRIMDLYUNSUP($3); } + | yNOT driveStrengthE delayE gateNotList ';' + { $$ = $4; APPLY_STRENGTH_TO_LIST($$, $2, AssignW); PRIMDLYUNSUP($3); } + | yNOTIF0 driveStrengthE delayE gateNotif0List ';' + { $$ = $4; STRENGTHUNSUP($2); PRIMDLYUNSUP($3); } + | yNOTIF1 driveStrengthE delayE gateNotif1List ';' + { $$ = $4; STRENGTHUNSUP($2); PRIMDLYUNSUP($3); } + | yAND driveStrengthE delayE gateAndList ';' + { $$ = $4; APPLY_STRENGTH_TO_LIST($$, $2, AssignW); PRIMDLYUNSUP($3); } + | yNAND driveStrengthE delayE gateNandList ';' + { $$ = $4; APPLY_STRENGTH_TO_LIST($$, $2, AssignW); PRIMDLYUNSUP($3); } + | yOR driveStrengthE delayE gateOrList ';' + { $$ = $4; APPLY_STRENGTH_TO_LIST($$, $2, AssignW); PRIMDLYUNSUP($3); } + | yNOR driveStrengthE delayE gateNorList ';' + { $$ = $4; APPLY_STRENGTH_TO_LIST($$, $2, AssignW); PRIMDLYUNSUP($3); } + | yXOR driveStrengthE delayE gateXorList ';' + { $$ = $4; APPLY_STRENGTH_TO_LIST($$, $2, AssignW); PRIMDLYUNSUP($3); } + | yXNOR driveStrengthE delayE gateXnorList ';' + { $$ = $4; APPLY_STRENGTH_TO_LIST($$, $2, AssignW); PRIMDLYUNSUP($3); } | yPULLUP delayE gatePullupList ';' { $$ = $3; PRIMDLYUNSUP($2); } | yPULLDOWN delayE gatePulldownList ';' { $$ = $3; PRIMDLYUNSUP($2); } | yNMOS delayE gateBufif1List ';' { $$ = $3; PRIMDLYUNSUP($2); } // ~=bufif1, as don't have strengths yet @@ -4901,21 +4958,33 @@ gatePinExpr: expr { $$ = GRAMMARP->createGatePin($1); } ; -// This list is also hardcoded in VParseLex.l -strength: // IEEE: strength0+strength1 - plus HIGHZ/SMALL/MEDIUM/LARGE - ygenSTRENGTH { BBUNSUP($1, "Unsupported: Verilog 1995 strength specifiers"); } - | ySUPPLY0 { BBUNSUP($1, "Unsupported: Verilog 1995 strength specifiers"); } - | ySUPPLY1 { BBUNSUP($1, "Unsupported: Verilog 1995 strength specifiers"); } +strength0: + ySUPPLY0 { $$ = VStrength::SUPPLY; } + | ySTRONG0 { $$ = VStrength::STRONG; } + | yPULL0 { $$ = VStrength::PULL; } + | yWEAK0 { $$ = VStrength::WEAK; } ; -strengthSpecE: // IEEE: drive_strength + pullup_strength + pulldown_strength + charge_strength - plus empty - /* empty */ { } - | strengthSpec { } +strength1: + ySUPPLY1 { $$ = VStrength::SUPPLY; } + | ySTRONG1 { $$ = VStrength::STRONG; } + | yPULL1 { $$ = VStrength::PULL; } + | yWEAK1 { $$ = VStrength::WEAK; } ; -strengthSpec: // IEEE: drive_strength + pullup_strength + pulldown_strength + charge_strength - plus empty - yP_PAR__STRENGTH strength ')' { } - | yP_PAR__STRENGTH strength ',' strength ')' { } +driveStrengthE: + /* empty */ { $$ = nullptr; } + | driveStrength { $$ = $1; } + ; + + +driveStrength: + yP_PAR__STRENGTH strength0 ',' strength1 ')' { $$ = new AstStrengthSpec{$1, $2, $4}; } + | yP_PAR__STRENGTH strength1 ',' strength0 ')' { $$ = new AstStrengthSpec{$1, $4, $2}; } + | yP_PAR__STRENGTH strength0 ',' yHIGHZ1 ')' { BBUNSUP($4, "Unsupported: highz strength"); } + | yP_PAR__STRENGTH strength1 ',' yHIGHZ0 ')' { BBUNSUP($4, "Unsupported: highz strength"); } + | yP_PAR__STRENGTH yHIGHZ0 ',' strength1 ')' { BBUNSUP($2, "Unsupported: highz strength"); } + | yP_PAR__STRENGTH yHIGHZ1 ',' strength0 ')' { BBUNSUP($2, "Unsupported: highz strength"); } ; //************************************************ @@ -4925,12 +4994,12 @@ combinational_body: // IEEE: combinational_body + sequential_body yTABLE tableEntryList yENDTABLE { $$ = new AstUdpTable($1,$2); } ; -tableEntryList: // IEEE: { combinational_entry | sequential_entry } +tableEntryList: // IEEE: { combinational_entry | sequential_entry } tableEntry { $$ = $1; } - | tableEntryList tableEntry { $$ = $1->addNextNull($2); } + | tableEntryList tableEntry { $$ = addNextNull($1, $2); } ; -tableEntry: // IEEE: combinational_entry + sequential_entry +tableEntry: // IEEE: combinational_entry + sequential_entry yaTABLELINE { $$ = new AstUdpTableLine($1,*$1); } | error { $$ = nullptr; } ; @@ -5023,7 +5092,7 @@ variable_lvalueConcList: // IEEE: part of variable_lvalue: '{' variable_l //UNSUPvariable_lvalueList: // IEEE: part of variable_lvalue: variable_lvalue { ',' variable_lvalue } //UNSUP variable_lvalue { $$ = $1; } -//UNSUP | variable_lvalueList ',' variable_lvalue { $$ = AstNode::addNextNull($1, $3); } +//UNSUP | variable_lvalueList ',' variable_lvalue { $$ = addNextNull($1, $3); } //UNSUP ; // VarRef to dotted, and/or arrayed, and/or bit-ranged variable @@ -5101,9 +5170,9 @@ idArrayedForeach: // IEEE: id + select (under foreach expression) // // IEEE: loop_variables (under foreach expression) // // To avoid conflicts we allow expr as first element, must post-check | idArrayed '[' expr ',' loop_variables ']' - { $3 = AstNode::addNextNull($3, $5); $$ = new AstSelLoopVars($2, $1, $3); } + { $3 = addNextNull($3, $5); $$ = new AstSelLoopVars($2, $1, $3); } | idArrayed '[' ',' loop_variables ']' - { $4 = AstNode::addNextNull(new AstEmpty{$3}, $4); $$ = new AstSelLoopVars($2, $1, $4); } + { $4 = addNextNull(static_cast(new AstEmpty{$3}), $4); $$ = new AstSelLoopVars($2, $1, $4); } ; // VarRef without any dots or vectorizaion @@ -5182,7 +5251,7 @@ clocking_declaration: // IEEE: clocking_declaration (INCOMPLE //UNSUPclocking_itemList: // IEEE: [ clocking_item ] //UNSUP clocking_item { $$ = $1; } -//UNSUP | clocking_itemList clocking_item { $$ = AstNode::addNextNull($1, $2); } +//UNSUP | clocking_itemList clocking_item { $$ = addNextNull($1, $2); } //UNSUP ; //UNSUPclocking_item: // ==IEEE: clocking_item @@ -5487,7 +5556,7 @@ property_spec: // IEEE: property_spec //UNSUPproperty_case_itemList: // IEEE: {property_case_item} //UNSUP property_case_item { $$ = $1; } -//UNSUP | property_case_itemList ',' property_case_item { $$ = AstNode::addNextNull($1, $3); } +//UNSUP | property_case_itemList ',' property_case_item { $$ = addNextNull($1, $3); } //UNSUP ; //UNSUPproperty_case_item: // ==IEEE: property_case_item @@ -5744,7 +5813,7 @@ complex_pexpr: // IEEE: part of property_expr, see comments there //UNSUPcoverage_spec_or_optionList: // IEEE: {coverage_spec_or_option} //UNSUP coverage_spec_or_option { $$ = $1; } -//UNSUP | coverage_spec_or_optionList coverage_spec_or_option { $$ = AstNode::addNextNull($1, $2); } +//UNSUP | coverage_spec_or_optionList coverage_spec_or_option { $$ = addNextNull($1, $2); } //UNSUP ; //UNSUPcoverage_spec_or_option: // ==IEEE: coverage_spec_or_option @@ -5785,7 +5854,7 @@ complex_pexpr: // IEEE: part of property_expr, see comments there //UNSUPbins_or_optionsList: // IEEE: { bins_or_options ';' } //UNSUP bins_or_options ';' { $$ = $1; } -//UNSUP | bins_or_optionsList bins_or_options ';' { $$ = AstNode::addNextNull($1, $2); } +//UNSUP | bins_or_optionsList bins_or_options ';' { $$ = addNextNull($1, $2); } //UNSUP ; //UNSUPbins_or_options: // ==IEEE: bins_or_options @@ -5821,7 +5890,7 @@ complex_pexpr: // IEEE: part of property_expr, see comments there //UNSUPcovergroup_range_list: // ==IEEE: covergroup_range_list //UNSUP covergroup_value_range { $$ = $1; } -//UNSUP | covergroup_range_list ',' covergroup_value_range { $$ = AstNode::addNextNull($1, $3); } +//UNSUP | covergroup_range_list ',' covergroup_value_range { $$ = addNextNull($1, $3); } //UNSUP ; //UNSUPtrans_list: // ==IEEE: trans_list @@ -5848,7 +5917,7 @@ complex_pexpr: // IEEE: part of property_expr, see comments there //UNSUPrepeat_range: // ==IEEE: repeat_range //UNSUP cgexpr { $$ = $1; } -//UNSUP | cgexpr ':' cgexpr { $$ = AstNode::addNextNull($1, $3); } +//UNSUP | cgexpr ':' cgexpr { $$ = addNextNull($1, $3); } //UNSUP ; //UNSUPcover_cross: // ==IEEE: cover_cross @@ -5857,13 +5926,13 @@ complex_pexpr: // IEEE: part of property_expr, see comments there //UNSUP ; //UNSUPlist_of_cross_items: // ==IEEE: list_of_cross_items -//UNSUP cross_item ',' cross_item { $$ = AstNode::addNextNull($1, $3); } +//UNSUP cross_item ',' cross_item { $$ = addNextNull($1, $3); } //UNSUP | cross_item ',' cross_item ',' cross_itemList { } //UNSUP ; //UNSUPcross_itemList: // IEEE: part of list_of_cross_items //UNSUP cross_item { $$ = nullptr; } -//UNSUP | cross_itemList ',' cross_item { $$ = AstNode::addNextNull($1, $3); } +//UNSUP | cross_itemList ',' cross_item { $$ = addNextNull($1, $3); } //UNSUP ; //UNSUPcross_item: // ==IEEE: cross_item @@ -5879,7 +5948,7 @@ complex_pexpr: // IEEE: part of property_expr, see comments there //UNSUPcross_body_itemSemiList: // IEEE: part of cross_body //UNSUP cross_body_item ';' { $$ = $1; } -//UNSUP | cross_body_itemSemiList cross_body_item ';' { $$ = AstNode::addNextNull($1, $2); } +//UNSUP | cross_body_itemSemiList cross_body_item ';' { $$ = addNextNull($1, $2); } //UNSUP ; //UNSUPcross_body_item: // ==IEEE: cross_body_item @@ -5959,7 +6028,7 @@ complex_pexpr: // IEEE: part of property_expr, see comments there //UNSUPproductionList: // IEEE: production+ //UNSUP production { $$ = $1; } -//UNSUP | productionList production { $$ = AstNode::addNextNull($1, $2); } +//UNSUP | productionList production { $$ = addNextNull($1, $2); } //UNSUP ; //UNSUPproduction: // ==IEEE: production @@ -5975,7 +6044,7 @@ complex_pexpr: // IEEE: part of property_expr, see comments there //UNSUPrs_ruleList: // IEEE: rs_rule+ part of production //UNSUP rs_rule { $$ = $1; } -//UNSUP | rs_ruleList '|' rs_rule { $$ = AstNode::addNextNull($1, $3); } +//UNSUP | rs_ruleList '|' rs_rule { $$ = addNextNull($1, $3); } //UNSUP ; //UNSUPrs_rule: // ==IEEE: rs_rule @@ -6003,7 +6072,7 @@ complex_pexpr: // IEEE: part of property_expr, see comments there //UNSUPrs_code_blockItemList: // IEEE: part of rs_code_block //UNSUP rs_code_blockItem { $$ = $1; } -//UNSUP | rs_code_blockItemList rs_code_blockItem { $$ = AstNode::addNextNull($1, $2); } +//UNSUP | rs_code_blockItemList rs_code_blockItem { $$ = addNextNull($1, $2); } //UNSUP ; //UNSUPrs_code_blockItem: // IEEE: part of rs_code_block @@ -6013,7 +6082,7 @@ complex_pexpr: // IEEE: part of property_expr, see comments there //UNSUPrs_prodList: // IEEE: rs_prod+ //UNSUP rs_prod { $$ = $1; } -//UNSUP | rs_prodList rs_prod { $$ = AstNode::addNextNull($1, $2); } +//UNSUP | rs_prodList rs_prod { $$ = addNextNull($1, $2); } //UNSUP ; //UNSUPrs_prod: // ==IEEE: rs_prod @@ -6030,7 +6099,7 @@ complex_pexpr: // IEEE: part of property_expr, see comments there //UNSUPproduction_itemList: // IEEE: production_item+ //UNSUP production_item { $$ = $1; } -//UNSUP | production_itemList production_item { $$ = AstNode::addNextNull($1, $2); } +//UNSUP | production_itemList production_item { $$ = addNextNull($1, $2); } //UNSUP ; //UNSUPproduction_item: // ==IEEE: production_item @@ -6040,7 +6109,7 @@ complex_pexpr: // IEEE: part of property_expr, see comments there //UNSUPrs_case_itemList: // IEEE: rs_case_item+ //UNSUP rs_case_item { $$ = $1; } -//UNSUP | rs_case_itemList rs_case_item { $$ = AstNode::addNextNull($1, $2); } +//UNSUP | rs_case_itemList rs_case_item { $$ = addNextNull($1, $2); } //UNSUP ; //UNSUPrs_case_item: // ==IEEE: rs_case_item @@ -6076,7 +6145,7 @@ complex_pexpr: // IEEE: part of property_expr, see comments there //UNSUPchecker_or_generate_itemList: // IEEE: { checker_or_generate_itemList } //UNSUP checker_or_generate_item { $$ = $1; } -//UNSUP | checker_or_generate_itemList checker_or_generate_item { $$ = AstNode::addNextNull($1, $2); } +//UNSUP | checker_or_generate_itemList checker_or_generate_item { $$ = addNextNull($1, $2); } //UNSUP ; //UNSUPchecker_or_generate_item: // ==IEEE: checker_or_generate_item @@ -6160,14 +6229,14 @@ classVirtualE: | yVIRTUAL__CLASS { $$ = true; } ; -classExtendsE: // IEEE: part of class_declaration +classExtendsE: // IEEE: part of class_declaration // // The classExtendsE rule relys on classFront having the // // new class scope correct via classFront /* empty */ { $$ = nullptr; $$ = nullptr; } | yEXTENDS classExtendsList { $$ = $2; $$ = $2; } ; -classExtendsList: // IEEE: part of class_declaration +classExtendsList: // IEEE: part of class_declaration classExtendsOne { $$ = $1; $$ = $1; } | classExtendsList ',' classExtendsOne { $$ = $3; $$ = $3; @@ -6175,7 +6244,7 @@ classExtendsList: // IEEE: part of class_declaration "and unsupported for interface classes."); } ; -classExtendsOne: // IEEE: part of class_declaration +classExtendsOne: // IEEE: part of class_declaration class_typeExtImpList { $$ = new AstClassExtends($1->fileline(), $1); $$ = $1; } @@ -6195,7 +6264,7 @@ classImplementsE: // IEEE: part of class_declaration classImplementsList: // IEEE: part of class_declaration // // All 1800-2012 class_typeExtImpList { $$ = nullptr; BBUNSUP($1, "Unsupported: implements class"); } - | classImplementsList ',' class_typeExtImpList { $$ = AstNode::addNextNull($1, $3); } + | classImplementsList ',' class_typeExtImpList { $$ = addNextNull($1, $3); } ; class_typeExtImpList: // IEEE: class_type: "[package_scope] id [ parameter_value_assignment ]" @@ -6322,7 +6391,7 @@ class_itemListE: class_itemList: class_item { $$ = $1; } - | class_itemList class_item { $$ = AstNode::addNextNull($1, $2); } + | class_itemList class_item { $$ = addNextNull($1, $2); } ; class_item: // ==IEEE: class_item @@ -6407,7 +6476,7 @@ constraint_block: // ==IEEE: constraint_block constraint_block_itemList: // IEEE: { constraint_block_item } constraint_block_item { $$ = $1; } - | constraint_block_itemList constraint_block_item { $$ = AstNode::addNextNull($1, $2); } + | constraint_block_itemList constraint_block_item { $$ = addNextNull($1, $2); } ; constraint_block_item: // ==IEEE: constraint_block_item @@ -6418,7 +6487,7 @@ constraint_block_item: // ==IEEE: constraint_block_item solve_before_list: // ==IEEE: solve_before_list constraint_primary { $$ = $1; } - | solve_before_list ',' constraint_primary { $$ = AstNode::addNextNull($1, $3); } + | solve_before_list ',' constraint_primary { $$ = addNextNull($1, $3); } ; constraint_primary: // ==IEEE: constraint_primary @@ -6429,7 +6498,7 @@ constraint_primary: // ==IEEE: constraint_primary constraint_expressionList: // ==IEEE: { constraint_expression } constraint_expression { $$ = $1; } - | constraint_expressionList constraint_expression { $$ = AstNode::addNextNull($1, $2); } + | constraint_expressionList constraint_expression { $$ = addNextNull($1, $2); } ; constraint_expression: // ==IEEE: constraint_expression @@ -6457,7 +6526,7 @@ constraint_set: // ==IEEE: constraint_set dist_list: // ==IEEE: dist_list dist_item { $$ = $1; } - | dist_list ',' dist_item { $$ = AstNode::addNextNull($1, $3); } + | dist_list ',' dist_item { $$ = addNextNull($1, $3); } ; dist_item: // ==IEEE: dist_item + dist_weight @@ -6572,7 +6641,7 @@ vltOffFront: | yVLT_TRACING_OFF { $$ = V3ErrorCode::I_TRACING; } | yVLT_LINT_OFF { $$ = V3ErrorCode::I_LINT; } | yVLT_LINT_OFF yVLT_D_RULE idAny - { $$ = V3ErrorCode((*$3).c_str()); + { $$ = V3ErrorCode{(*$3).c_str()}; if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown Error Code: " << *$3); } } ; @@ -6581,7 +6650,7 @@ vltOnFront: | yVLT_TRACING_ON { $$ = V3ErrorCode::I_TRACING; } | yVLT_LINT_ON { $$ = V3ErrorCode::I_LINT; } | yVLT_LINT_ON yVLT_D_RULE idAny - { $$ = V3ErrorCode((*$3).c_str()); + { $$ = V3ErrorCode{(*$3).c_str()}; if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown Error Code: " << *$3); } } ; diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 22a2a67f8..da738d16a 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -235,7 +235,7 @@ sub parameter { elsif ($param =~ /\.pl/) { push @opt_tests, $param; } - elsif ($param =~ /^-?(-debugi|-dump-treei)/) { + elsif ($param =~ /^-?(-debugi|-dumpi)/) { push @Opt_Driver_Verilator_Flags, $param; $_Parameter_Next_Level = $param; } @@ -1845,7 +1845,7 @@ sub _make_main { if ($self->{savable}) { $fh->print(" const char* save_time_strp = contextp->commandArgsPlusMatch(\"save_time=\");\n"); - $fh->print(" unsigned int save_time = !save_time_strp[0] ? 0 : atoi(save_time_strp+strlen(\"+save_time=\"));\n"); + $fh->print(" unsigned int save_time = !save_time_strp[0] ? 0 : std::atoi(save_time_strp + std::strlen(\"+save_time=\"));\n"); $fh->print(" const char* save_restore_strp = contextp->commandArgsPlusMatch(\"save_restore=\");\n"); $fh->print(" unsigned int save_restore = !save_restore_strp[0] ? 0 : 1;\n"); } diff --git a/test_regress/t/TestCheck.h b/test_regress/t/TestCheck.h index ac42dde3b..2f8cf2283 100644 --- a/test_regress/t/TestCheck.h +++ b/test_regress/t/TestCheck.h @@ -34,7 +34,7 @@ static const bool verbose = false; #define TEST_CHECK_EQ(got, exp) TEST_CHECK(got, exp, ((got) == (exp))); #define TEST_CHECK_NE(got, exp) TEST_CHECK(got, exp, ((got) != (exp))); -#define TEST_CHECK_CSTR(got, exp) TEST_CHECK(got, exp, 0 == strcmp((got), (exp))); +#define TEST_CHECK_CSTR(got, exp) TEST_CHECK(got, exp, 0 == std::strcmp((got), (exp))); #define TEST_CHECK_HEX_EQ(got, exp) \ do { \ diff --git a/test_regress/t/TestSimulator.h b/test_regress/t/TestSimulator.h index 6272887d8..c25304f6e 100644 --- a/test_regress/t/TestSimulator.h +++ b/test_regress/t/TestSimulator.h @@ -28,13 +28,13 @@ private: public: TestSimulator() { vpi_get_vlog_info(&m_info); - if (0 == strcmp(m_info.product, "Verilator")) { + if (0 == std::strcmp(m_info.product, "Verilator")) { m_simulators.verilator = true; - } else if (0 == strcmp(m_info.product, "Verilator")) { + } else if (0 == std::strcmp(m_info.product, "Verilator")) { m_simulators.icarus = true; } else if (0 == strncmp(m_info.product, "Chronologic Simulation VCS", - strlen("Chronologic Simulation VCS"))) { + std::strlen("Chronologic Simulation VCS"))) { m_simulators.vcs = true; } else { printf("%%Warning: %s:%d: Unknown simulator in TestSimulator.h: %s\n", __FILE__, diff --git a/test_regress/t/TestVpi.h b/test_regress/t/TestVpi.h index 389707823..40734b7c6 100644 --- a/test_regress/t/TestVpi.h +++ b/test_regress/t/TestVpi.h @@ -29,7 +29,7 @@ public: , m_freeit(true) {} ~TestVpiHandle() { release(); } operator vpiHandle() const { return m_handle; } - inline TestVpiHandle& operator=(vpiHandle h) { + TestVpiHandle& operator=(vpiHandle h) { release(); m_handle = h; return *this; diff --git a/test_regress/t/t_EXAMPLE.v b/test_regress/t/t_EXAMPLE.v index 0e3a9b428..236e0f85d 100644 --- a/test_regress/t/t_EXAMPLE.v +++ b/test_regress/t/t_EXAMPLE.v @@ -13,7 +13,7 @@ // please note it here, otherwise:** // // This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2022 by ____YOUR_NAME_HERE____. +// any use, without warranty, 2022 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 module t(/*AUTOARG*/ diff --git a/test_regress/t/t_ccache_report.pl b/test_regress/t/t_ccache_report.pl index a17c2b02e..790bbf9f0 100755 --- a/test_regress/t/t_ccache_report.pl +++ b/test_regress/t/t_ccache_report.pl @@ -13,36 +13,37 @@ scenarios(vlt => 1); if (!$Self->cfg_with_ccache) { skip("Requires configuring with ccache"); } +else { + top_filename("t_a1_first_cc.v"); -top_filename("t_a1_first_cc.v"); + # This test requires rebuilding the object files to check the ccache log + foreach my $filename (glob("$Self->{obj_dir}/*.o")) { + print "rm $filename\n" if $Self->{verbose}; + unlink $filename; + } -# This test requires rebuilding the object files to check the ccache log -foreach my $filename (glob("$Self->{obj_dir}/*.o")) { - print "rm $filename\n" if $Self->{verbose}; - unlink $filename; + compile( + verilator_flags2 => ['--trace'], + make_flags => "ccache-report" + ); + + my $report = "$Self->{obj_dir}/$Self->{VM_PREFIX}__ccache_report.txt"; + + # We do not actually want to make this test depend on whether the file was + # cached or not, so trim the report to ignore actual caching behaviour + run(cmd => ["sed", "-i", "-e", "'s/ : .*/ : IGNORED/; /|/s/.*/IGNORED/;'", $report]); + files_identical($report, "t/$Self->{name}__ccache_report_initial.out"); + + # Now rebuild again (should be all up to date) + run( + logfile => "$Self->{obj_dir}/rebuild.log", + cmd => ["make", "-C", $Self->{obj_dir}, + "-f", "$Self->{VM_PREFIX}.mk", + $Self->{VM_PREFIX}, "ccache-report"] + ); + + files_identical($report, "t/$Self->{name}__ccache_report_rebuild.out"); } -compile( - verilator_flags2 => ['--trace'], - make_flags => "ccache-report" - ); - -my $report = "$Self->{obj_dir}/$Self->{VM_PREFIX}__ccache_report.txt"; - -# We do not actually want to make this test depend on whether the file was -# cached or not, so trim the report to ignore actual caching behaviour -run(cmd => ["sed", "-i", "-e", "'s/ : .*/ : IGNORED/; /|/s/.*/IGNORED/;'", $report]); -files_identical($report, "t/$Self->{name}__ccache_report_initial.out"); - -# Now rebuild again (should be all up to date) -run( - logfile => "$Self->{obj_dir}/rebuild.log", - cmd => ["make", "-C", $Self->{obj_dir}, - "-f", "$Self->{VM_PREFIX}.mk", - $Self->{VM_PREFIX}, "ccache-report"] - ); - -files_identical($report, "t/$Self->{name}__ccache_report_rebuild.out"); - ok(1); 1; diff --git a/test_regress/t/t_class1.v b/test_regress/t/t_class1.v index b584c5be6..c10125c51 100644 --- a/test_regress/t/t_class1.v +++ b/test_regress/t/t_class1.v @@ -12,14 +12,20 @@ class Cls; endclass : Cls module t (/*AUTOARG*/); + typedef Cls Cls2; + initial begin Cls c; + Cls2 c2; if (c != null) $stop; if (c) $stop; + if (c2) $stop; $display("Display: null = \"%p\"", c); // null c = new; + c2 = new; if (c == null) $stop; if (!c) $stop; + if (!c2) $stop; $display("Display: newed = \"%p\"", c); // '{imembera:0, imemberb:0} c.imembera = 10; c.imemberb = 20; diff --git a/test_regress/t/t_void_queue_ops.pl b/test_regress/t/t_class_method_str_literal.pl similarity index 100% rename from test_regress/t/t_void_queue_ops.pl rename to test_regress/t/t_class_method_str_literal.pl diff --git a/test_regress/t/t_class_method_str_literal.v b/test_regress/t/t_class_method_str_literal.v new file mode 100644 index 000000000..3e5e9225d --- /dev/null +++ b/test_regress/t/t_class_method_str_literal.v @@ -0,0 +1,28 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + +class T; + function automatic void print_str(input string a_string); + $display(a_string); + endfunction + + static function automatic void static_print_str(input string a_string); + $display(a_string); + endfunction +endclass + + +initial begin + T t_c = new; + t_c.print_str("function though member"); + t_c.static_print_str("static function through member"); + T::static_print_str("static function through class"); + $write("*-* All Finished *-*\n"); + $finish; +end +endmodule diff --git a/test_regress/t/t_debug_emitv.pl b/test_regress/t/t_debug_emitv.pl index 863c22c75..91be564c7 100755 --- a/test_regress/t/t_debug_emitv.pl +++ b/test_regress/t/t_debug_emitv.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); lint( # We also have dump-tree turned on, so hit a lot of AstNode*::dump() functions # Likewise XML - v_flags => ["--lint-only --dump-treei 9 --dump-treei-V3EmitV 9 --debug-emitv"], + v_flags => ["--lint-only --dumpi-tree 9 --dumpi-V3EmitV 9 --debug-emitv"], ); files_identical(glob_one("$Self->{obj_dir}/$Self->{VM_PREFIX}_*_width.tree.v"), $Self->{golden_filename}); diff --git a/test_regress/t/t_debug_emitv_addrids.pl b/test_regress/t/t_debug_emitv_addrids.pl index 40070d6e5..183f2dd13 100755 --- a/test_regress/t/t_debug_emitv_addrids.pl +++ b/test_regress/t/t_debug_emitv_addrids.pl @@ -15,7 +15,7 @@ top_filename("t/t_debug_emitv.v"); lint( # We also have dump-tree turned on, so hit a lot of AstNode*::dump() functions # Likewise XML - v_flags => ["--lint-only --dump-treei 9 --dump-tree-addrids"], + v_flags => ["--lint-only --dumpi-tree 9 --dump-tree-addrids"], ); ok(1); diff --git a/test_regress/t/t_write_format_bug.out b/test_regress/t/t_display_concat2.out similarity index 100% rename from test_regress/t/t_write_format_bug.out rename to test_regress/t/t_display_concat2.out diff --git a/test_regress/t/t_write_format_bug.pl b/test_regress/t/t_display_concat2.pl similarity index 100% rename from test_regress/t/t_write_format_bug.pl rename to test_regress/t/t_display_concat2.pl diff --git a/test_regress/t/t_write_format_bug.v b/test_regress/t/t_display_concat2.v similarity index 100% rename from test_regress/t/t_write_format_bug.v rename to test_regress/t/t_display_concat2.v diff --git a/test_regress/t/t_dist_cppstyle.pl b/test_regress/t/t_dist_cppstyle.pl new file mode 100755 index 000000000..7a8f23e5d --- /dev/null +++ b/test_regress/t/t_dist_cppstyle.pl @@ -0,0 +1,80 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Primitive C++ style checker +# +# Copyright 2022 by Geza Lore. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(dist => 1); + +my $root = ".."; + +### Must trim output before and after our file list +my %files = %{get_source_files($root)}; + +foreach my $file (sort keys %files) { + my $filename = "$root/$file"; + next if !-f $filename; # git file might be deleted but not yet staged + next unless $file =~ /\.(h|c|cpp)(\.in)?$/; + next if $file =~ /gtkwave/; + + my $contents = file_contents($filename); + + checkPattern($filename, $contents, + qr/[^\/]*virtual[^{};]+override/, + "'virtual' keyword is redundant on 'override' method"); + + checkPattern($filename, $contents, + qr/ \s*(\w+ )*\s*(inline) [^;]+?\([^;]*?\)[^;]+?(?:{|:|=\s*default)/, + "'inline' keyword is redundant on method definitions inside classes"); + + checkPattern($filename, $contents, + qr/(?\n)inline \S+ [^;:(]+::[^;:(]+\([^;]*\)[^;]+{/, + "Use 'inline' only on declaration inside classes (except for template specializatoins)"); + + if ($file =~ /\.(c|cpp)/) { + checkPattern($filename, $contents, + qr/(\w+\s+)*(inline)/, + "'inline' keyword is on functions defined in .cpp files"); + } +} + +ok(1); +1; + +sub get_source_files { + my $root = shift; + my $git_files = `cd $root && git ls-files`; + print "MF $git_files\n" if $Self->{verbose}; + my %files; + foreach my $file (split /\s+/, $git_files) { + next if $file eq ''; + $files{$file} |= 1; + } + return \%files; +} + +sub checkPattern { + my $filename = shift; + my $contents = shift; + my $pattern = shift; + my $message = shift; + + my $offset = 0; + my $buffer = $contents; + while ($buffer =~ s/.*?^($pattern)//sm) { + my $lineno = offset_to_lineno($contents, $offset + $-[-1]); + $offset += $+[1]; + error("$filename:$lineno: $message"); + } +} + +sub offset_to_lineno { + my $contents = shift; + my $offset = shift; + my $count = (substr $contents, 0, $offset) =~ tr/\n//; + return $count + 1; +} diff --git a/test_regress/t/t_dotfiles.pl b/test_regress/t/t_dotfiles.pl index a9b52715e..9df77e2ca 100755 --- a/test_regress/t/t_dotfiles.pl +++ b/test_regress/t/t_dotfiles.pl @@ -14,7 +14,7 @@ scenarios(vltmt => 1); top_filename("t/t_gen_alw.v"); compile( - v_flags2 => ["--debug --debugi 5"], + v_flags2 => ["--dumpi-graph 6"], threads => 2 ); diff --git a/test_regress/t/t_dpi_arg_inout_type.cpp b/test_regress/t/t_dpi_arg_inout_type.cpp index a5c346d8f..f5b109b39 100644 --- a/test_regress/t/t_dpi_arg_inout_type.cpp +++ b/test_regress/t/t_dpi_arg_inout_type.cpp @@ -168,10 +168,10 @@ void i_string(const char** x) { static int n = 0; printf("i_string %d\n", n); if (n++ % 2 == 0) { - if (strcmp(*x, "Hello") != 0) stop(); + if (std::strcmp(*x, "Hello") != 0) stop(); *x = "Good"; } else { - if (strcmp(*x, "World") != 0) stop(); + if (std::strcmp(*x, "World") != 0) stop(); *x = "Bye"; } } @@ -296,10 +296,10 @@ void i_string_t(const char** x) { static int n = 0; printf("i_string_t %d\n", n); if (n++ % 2 == 0) { - if (strcmp(*x, "World") != 0) stop(); + if (std::strcmp(*x, "World") != 0) stop(); *x = "Bye"; } else { - if (strcmp(*x, "Hello") != 0) stop(); + if (std::strcmp(*x, "Hello") != 0) stop(); *x = "Good"; } } @@ -962,10 +962,10 @@ void check_exports() { e_string(&x_string); if ((n % 2) == 0) { if (x_chandle) stop(); - if (strcmp(x_string, "Hello") != 0) stop(); + if (std::strcmp(x_string, "Hello") != 0) stop(); } else { if (x_chandle) stop(); - if (strcmp(x_string, "World") != 0) stop(); + if (std::strcmp(x_string, "World") != 0) stop(); } x_bit = n % 2; @@ -1045,10 +1045,10 @@ void check_exports() { e_string_t(&x_string_t); if ((n % 2) == 0) { if (x_chandle_t != NULL) stop(); - if (strcmp(x_string_t, "World") != 0) stop(); + if (std::strcmp(x_string_t, "World") != 0) stop(); } else { if (x_chandle_t != NULL) stop(); - if (strcmp(x_string_t, "Hello") != 0) stop(); + if (std::strcmp(x_string_t, "Hello") != 0) stop(); } x_bit_t = n % 2; diff --git a/test_regress/t/t_dpi_arg_input_type.cpp b/test_regress/t/t_dpi_arg_input_type.cpp index 1593e1dfc..ee7f56d79 100644 --- a/test_regress/t/t_dpi_arg_input_type.cpp +++ b/test_regress/t/t_dpi_arg_input_type.cpp @@ -155,9 +155,9 @@ void i_string(const char* i) { static int n = 0; printf("i_string %d\n", n); if (n++ % 2 == 0) { - if (strcmp(i, "World") != 0) stop(); + if (std::strcmp(i, "World") != 0) stop(); } else { - if (strcmp(i, "Hello") != 0) stop(); + if (std::strcmp(i, "Hello") != 0) stop(); } } @@ -266,9 +266,9 @@ void i_string_t(const char* i) { static int n = 0; printf("i_string_t %d\n", n); if (n++ % 2 == 0) { - if (strcmp(i, "World") != 0) stop(); + if (std::strcmp(i, "World") != 0) stop(); } else { - if (strcmp(i, "Hello") != 0) stop(); + if (std::strcmp(i, "Hello") != 0) stop(); } } diff --git a/test_regress/t/t_dpi_arg_output_type.cpp b/test_regress/t/t_dpi_arg_output_type.cpp index cf127ee6e..b8eda4a74 100644 --- a/test_regress/t/t_dpi_arg_output_type.cpp +++ b/test_regress/t/t_dpi_arg_output_type.cpp @@ -711,9 +711,9 @@ void check_exports() { e_string(&x_string); if ((n % 2) == 0) { - if (strcmp(x_string, "Hello") != 0) stop(); + if (std::strcmp(x_string, "Hello") != 0) stop(); } else { - if (strcmp(x_string, "World") != 0) stop(); + if (std::strcmp(x_string, "World") != 0) stop(); } e_bit(&x_bit); @@ -772,9 +772,9 @@ void check_exports() { e_string_t(&x_string_t); if ((n % 2) == 0) { - if (strcmp(x_string_t, "Hello") != 0) stop(); + if (std::strcmp(x_string_t, "Hello") != 0) stop(); } else { - if (strcmp(x_string_t, "World") != 0) stop(); + if (std::strcmp(x_string_t, "World") != 0) stop(); } e_bit_t(&x_bit_t); diff --git a/test_regress/t/t_dpi_export_c.cpp b/test_regress/t/t_dpi_export_c.cpp index da9fee221..8b60a1c66 100644 --- a/test_regress/t/t_dpi_export_c.cpp +++ b/test_regress/t/t_dpi_export_c.cpp @@ -115,9 +115,10 @@ int dpix_run_tests() { #ifndef CADENCE // Unimplemented; how hard is it? printf("svDpiVersion: %s\n", svDpiVersion()); - CHECK_RESULT( - bool, - strcmp(svDpiVersion(), "1800-2005") == 0 || strcmp(svDpiVersion(), "P1800-2005") == 0, 1); + CHECK_RESULT(bool, + std::strcmp(svDpiVersion(), "1800-2005") == 0 + || std::strcmp(svDpiVersion(), "P1800-2005") == 0, + 1); #endif CHECK_RESULT(int, dpix_int123(), 0x123); diff --git a/test_regress/t/t_dpi_result_type.cpp b/test_regress/t/t_dpi_result_type.cpp index a0d7b3cb5..bc8314a15 100644 --- a/test_regress/t/t_dpi_result_type.cpp +++ b/test_regress/t/t_dpi_result_type.cpp @@ -303,9 +303,9 @@ void check_exports() { #endif if (e_chandle()) stop(); if ((n % 2) == 0) { - if (strcmp(e_string(), "Hello") != 0) stop(); + if (std::strcmp(e_string(), "Hello") != 0) stop(); } else { - if (strcmp(e_string(), "World") != 0) stop(); + if (std::strcmp(e_string(), "World") != 0) stop(); } if (e_bit() != (n % 2)) stop(); if (e_logic() != !(n % 2)) stop(); @@ -327,9 +327,9 @@ void check_exports() { #endif if (e_chandle_t()) stop(); if ((n % 2) == 0) { - if (strcmp(e_string_t(), "Hello") != 0) stop(); + if (std::strcmp(e_string_t(), "Hello") != 0) stop(); } else { - if (strcmp(e_string_t(), "World") != 0) stop(); + if (std::strcmp(e_string_t(), "World") != 0) stop(); } if (e_bit_t() != (n % 2)) stop(); if (e_logic_t() != !(n % 2)) stop(); diff --git a/test_regress/t/t_dpi_string_c.cpp b/test_regress/t/t_dpi_string_c.cpp index 05b001886..9216d9316 100644 --- a/test_regress/t/t_dpi_string_c.cpp +++ b/test_regress/t/t_dpi_string_c.cpp @@ -39,5 +39,5 @@ extern int dpii_string(const char* s); int dpii_string(const char* s) { printf("dpii_string: %s\n", s); - return strlen(s); + return std::strlen(s); } diff --git a/test_regress/t/t_dpi_var.cpp b/test_regress/t/t_dpi_var.cpp index f35647d41..5f9ee79f1 100644 --- a/test_regress/t/t_dpi_var.cpp +++ b/test_regress/t/t_dpi_var.cpp @@ -60,9 +60,9 @@ void mon_scope_name(const char* namep) { #ifdef TEST_VERBOSE VL_PRINTF("- mon_scope_name('%s', \"%s\");\n", modp, namep); #endif - if (strcmp(namep, "t.sub")) + if (std::strcmp(namep, "t.sub")) vl_fatal(__FILE__, __LINE__, "", (std::string{"Unexp scope name "} + namep).c_str()); - if (strcmp(modp, "t.sub")) + if (std::strcmp(modp, "t.sub")) vl_fatal(__FILE__, __LINE__, "", (std::string{"Unexp dpiscope name "} + modp).c_str()); } diff --git a/test_regress/t/t_extend_class_c.h b/test_regress/t/t_extend_class_c.h index c5e98001b..a1cdd58dc 100644 --- a/test_regress/t/t_extend_class_c.h +++ b/test_regress/t/t_extend_class_c.h @@ -13,5 +13,5 @@ public: ~t_extend_class_c() = default; // METHODS // This function will be called from a instance created in Verilog - inline uint32_t my_math(uint32_t in) { return in + 1; } + uint32_t my_math(uint32_t in) { return in + 1; } }; diff --git a/test_regress/t/t_flag_build_dep_bin.pl b/test_regress/t/t_flag_build_dep_bin.pl new file mode 100755 index 000000000..13eaa6fe3 --- /dev/null +++ b/test_regress/t/t_flag_build_dep_bin.pl @@ -0,0 +1,20 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +compile( + v_flags2 => ['--build-dep-bin', 'path_to_exe'], + ); + +file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}__ver.d", qr/path_to_exe/); + +ok(1); +1; diff --git a/test_regress/t/t_flag_build_dep_bin.v b/test_regress/t/t_flag_build_dep_bin.v new file mode 100644 index 000000000..a56f76564 --- /dev/null +++ b/test_regress/t/t_flag_build_dep_bin.v @@ -0,0 +1,8 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2005 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); +endmodule diff --git a/test_regress/t/t_flag_build_jobs_and_j.pl b/test_regress/t/t_flag_build_jobs_and_j.pl new file mode 100755 index 000000000..356011fbf --- /dev/null +++ b/test_regress/t/t_flag_build_jobs_and_j.pl @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd.. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); +top_filename("t/t_flag_make_cmake.v"); + +compile( + verilator_make_cmake => 0, + verilator_make_gmake => 0, + verilator_flags2 => ['--exe --cc --build -j 10 --build-jobs 2 --stats', + '../' . $Self->{main_filename}], + ); + +execute( + check_finished => 1, + ); + +file_grep($Self->{stats}, qr/Build jobs: 2/); + +ok(1); +1; diff --git a/test_regress/t/t_flag_build_jobs_bad.out b/test_regress/t/t_flag_build_jobs_bad.out new file mode 100644 index 000000000..341b1b979 --- /dev/null +++ b/test_regress/t/t_flag_build_jobs_bad.out @@ -0,0 +1 @@ +%Error: --build-jobs requires a non-negative integer, but '-1' was passed diff --git a/test_regress/t/t_flag_j_bad.pl b/test_regress/t/t_flag_build_jobs_bad.pl similarity index 91% rename from test_regress/t/t_flag_j_bad.pl rename to test_regress/t/t_flag_build_jobs_bad.pl index ee3d0fdc8..8432e74c6 100755 --- a/test_regress/t/t_flag_j_bad.pl +++ b/test_regress/t/t_flag_build_jobs_bad.pl @@ -14,7 +14,7 @@ top_filename("t/t_flag_werror.v"); lint( fails => 1, - verilator_flags => [qw(-j 0 --build)], + verilator_flags => [qw(--build-jobs -1 --build)], expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_flag_j_bad.out b/test_regress/t/t_flag_j_bad.out deleted file mode 100644 index 2fe652c5d..000000000 --- a/test_regress/t/t_flag_j_bad.out +++ /dev/null @@ -1,2 +0,0 @@ -%Error: -j accepts positive integer, but '0' is passed -%Error: Exiting due to diff --git a/test_regress/t/t_flag_main.pl b/test_regress/t/t_flag_main.pl index 381004460..57041562f 100755 --- a/test_regress/t/t_flag_main.pl +++ b/test_regress/t/t_flag_main.pl @@ -11,6 +11,9 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( + verilator_flags => [# Custom as don't want -cc + "-Mdir $Self->{obj_dir}", + "--debug-check", ], verilator_flags2 => ['--exe --build --main'], verilator_make_cmake => 0, verilator_make_gmake => 0, diff --git a/test_regress/t/t_flag_prefix.pl b/test_regress/t/t_flag_prefix.pl new file mode 100755 index 000000000..adcce742d --- /dev/null +++ b/test_regress/t/t_flag_prefix.pl @@ -0,0 +1,49 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Geza Lore. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +compile( + verilator_flags2 => ["--prefix t_flag_prefix", # should be overridden + "--prefix Vprefix", + "--exe", "--main", "--stats", "--build"], + verilator_make_cmake => 0, + verilator_make_gmake => 0, + make_main => 0, + ); + +execute( + check_finished => 1, + executable => "$Self->{obj_dir}/Vprefix", + ); + +sub check_files { + foreach my $path (glob("$Self->{obj_dir}/*")) { + my $filename = substr $path, ((length $Self->{obj_dir}) + 1); + next if ($filename =~ /^.*\.log$/); + if ($filename =~ /t_flag_prefix/) { + error("bad filename $filename"); + next; + } + next if ($filename =~ /^(.*\.(o|a)|Vprefix)$/); + my $fh = IO::File->new("<$path") or error("$! $filenme"); + while (defined(my $line = $fh->getline)) { + $line =~ s/--prefix V?t_flag_prefix//g; + $line =~ s/obj_vlt\/t_flag_prefix//g; + $line =~ s/t\/t_flag_prefix\.v//g; + error("bad line in $filename: $line") if $line =~ /t_flag_prefix/; + } + } +} + +check_files(); + +ok(1); +1; diff --git a/test_regress/t/t_flag_prefix.v b/test_regress/t/t_flag_prefix.v new file mode 100755 index 000000000..00634520b --- /dev/null +++ b/test_regress/t/t_flag_prefix.v @@ -0,0 +1,35 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Geza Lore. +// SPDX-License-Identifier: CC0-1.0 + +module t; + sub sub(); +endmodule + +module sub; + // no_inline_module, so it goes into separate file + /* verilator no_inline_module */ + + // Goes into const pool which is separate file + wire bit [255:0] C = {32'h1111_1111, + 32'h2222_2222, + 32'h3333_3333, + 32'h4444_4444, + 32'h5555_5555, + 32'h6666_6666, + 32'h7777_7777, + 32'h8888_8888}; + + initial begin + // Note: Base index via $c to prevent optimization + $display("0x%32x", C[$c(0*32)+:32]); + $display("0x%32x", C[$c(2*32)+:32]); + $display("0x%32x", C[$c(4*32)+:32]); + $display("0x%32x", C[$c(6*32)+:32]); + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_gate_loop.pl b/test_regress/t/t_gate_loop.pl new file mode 100755 index 000000000..1d9caab1c --- /dev/null +++ b/test_regress/t/t_gate_loop.pl @@ -0,0 +1,18 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Geza Lore. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + verilator_flags2 => ["-Wno-UNOPTFLAT"] + ); + +ok(1); +1; diff --git a/test_regress/t/t_gate_loop.v b/test_regress/t/t_gate_loop.v new file mode 100644 index 000000000..13ce7c416 --- /dev/null +++ b/test_regress/t/t_gate_loop.v @@ -0,0 +1,14 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Geza Lore. +// SPDX-License-Identifier: CC0-1.0 + +module t; + wire a; + wire b; + wire c; + assign a = b; + assign b = c; + assign c = a; +endmodule diff --git a/test_regress/t/t_mailbox.out b/test_regress/t/t_mailbox.out index 5a7cc1581..4d5432212 100644 --- a/test_regress/t/t_mailbox.out +++ b/test_regress/t/t_mailbox.out @@ -1,4 +1,6 @@ %Error: t/t_mailbox.v:20:4: Can't find typedef: 'mailbox' - 20 | mailbox m; + 20 | mailbox #(int) m; | ^~~~~~~ -%Error: Exiting due to +%Error: Internal Error: t/t_mailbox.v:20:14: ../V3LinkDot.cpp:#: Pin not under instance? + 20 | mailbox #(int) m; + | ^~~ diff --git a/test_regress/t/t_mailbox.v b/test_regress/t/t_mailbox.v index 21eadf323..06ea1f834 100644 --- a/test_regress/t/t_mailbox.v +++ b/test_regress/t/t_mailbox.v @@ -17,7 +17,7 @@ // endclass module t(/*AUTOARG*/); - mailbox m; + mailbox #(int) m; int msg; int out; diff --git a/test_regress/t/t_mailbox_bad.out b/test_regress/t/t_mailbox_bad.out new file mode 100644 index 000000000..4d5432212 --- /dev/null +++ b/test_regress/t/t_mailbox_bad.out @@ -0,0 +1,6 @@ +%Error: t/t_mailbox.v:20:4: Can't find typedef: 'mailbox' + 20 | mailbox #(int) m; + | ^~~~~~~ +%Error: Internal Error: t/t_mailbox.v:20:14: ../V3LinkDot.cpp:#: Pin not under instance? + 20 | mailbox #(int) m; + | ^~~ diff --git a/test_regress/t/t_mailbox_bad.pl b/test_regress/t/t_mailbox_bad.pl new file mode 100755 index 000000000..8de551634 --- /dev/null +++ b/test_regress/t/t_mailbox_bad.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t_mailbox.v"); + +lint( + verilator_flags2 => ["--xml-only"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_mailbox_bad.v b/test_regress/t/t_mailbox_bad.v new file mode 100644 index 000000000..a8bcb84fc --- /dev/null +++ b/test_regress/t/t_mailbox_bad.v @@ -0,0 +1,17 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + mailbox #(int) m; + + initial begin + m = new(4); + if (m.bad_method() != 0) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_process.v b/test_regress/t/t_process.v index f6ee27bac..0d495ab17 100644 --- a/test_regress/t/t_process.v +++ b/test_regress/t/t_process.v @@ -6,16 +6,16 @@ // Methods defined by IEEE: // class process; -// enum state { FINISHED, RUNNING, WAITING, SUSPENDED, KILLED }; +// enum state { FINISHED, RUNNING, WAITING, SUSPENDED, KILLED }; // UVM uses KILLED, FINISHED // static function process self(); // function state status(); // function void kill(); // task await(); // Warn as unsupported (no UVM library use) // function void suspend(); // Warn as unsupported (no UVM library use) // function void resume(); // Warn as unsupported (no UVM library use) -// function void srandom( int seed ); // Just ignore? -// function string get_randstate(); // Just ignore? -// function void set_randstate( string state ); // Just ignore? +// function void srandom( int seed ); // Operate on all proceses for now? +// function string get_randstate(); // Operate on all proceses for now? +// function void set_randstate( string state ); // Operate on all proceses for now? // endclass module t(/*AUTOARG*/); diff --git a/test_regress/t/t_process_bad.out b/test_regress/t/t_process_bad.out new file mode 100644 index 000000000..a4ada3778 --- /dev/null +++ b/test_regress/t/t_process_bad.out @@ -0,0 +1,10 @@ +%Error: t/t_process.v:22:4: Can't find typedef: 'process' + 22 | process p; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_process.v:26:20: Unsupported: 'process' + 26 | p = process::self(); + | ^~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Internal Error: t/t_process.v:26:11: ../V3LinkDot.cpp:#: Bad package link + 26 | p = process::self(); + | ^~~~~~~ diff --git a/test_regress/t/t_process_bad.pl b/test_regress/t/t_process_bad.pl new file mode 100755 index 000000000..7be24ae56 --- /dev/null +++ b/test_regress/t/t_process_bad.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t_process.v"); + +lint( + verilator_flags2 => ["--xml-only"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_process_bad.v b/test_regress/t/t_process_bad.v new file mode 100644 index 000000000..d32afb72b --- /dev/null +++ b/test_regress/t/t_process_bad.v @@ -0,0 +1,20 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + process p; + + initial begin + if (p != null) $stop; + p = process::self(); + if (p.bad_method() != 0) $stop; + + p.bad_method_2(); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_queue_void_ops.pl b/test_regress/t/t_queue_void_ops.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_queue_void_ops.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_void_queue_ops.v b/test_regress/t/t_queue_void_ops.v similarity index 96% rename from test_regress/t/t_void_queue_ops.v rename to test_regress/t/t_queue_void_ops.v index f618cb876..b3363177c 100644 --- a/test_regress/t/t_void_queue_ops.v +++ b/test_regress/t/t_queue_void_ops.v @@ -1,3 +1,9 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + module t (/*AUTOARG*/ // Inputs diff --git a/test_regress/t/t_sc_names.cpp b/test_regress/t/t_sc_names.cpp index 6839252b0..6f73c4c1d 100644 --- a/test_regress/t/t_sc_names.cpp +++ b/test_regress/t/t_sc_names.cpp @@ -15,7 +15,7 @@ int sc_main(int argc, char* argv[]) { /* We expect to find clk in here. */ for (int i = 0; i < ch.size(); ++i) { - if (!strcmp(ch[i]->basename(), "clk")) found = true; + if (!std::strcmp(ch[i]->basename(), "clk")) found = true; } if (found) { diff --git a/test_regress/t/t_scope_map.cpp b/test_regress/t/t_scope_map.cpp index 9136c8ee3..d9f554d8b 100644 --- a/test_regress/t/t_scope_map.cpp +++ b/test_regress/t/t_scope_map.cpp @@ -100,7 +100,7 @@ int main(int argc, char** argv, char** env) { #endif // Clear out the data - memset(varData, 0, (varBits + 7) / 8); + std::memset(varData, 0, (varBits + 7) / 8); } } diff --git a/test_regress/t/t_semaphore.out b/test_regress/t/t_semaphore.out index 21345fd35..76d60e04d 100644 --- a/test_regress/t/t_semaphore.out +++ b/test_regress/t/t_semaphore.out @@ -1,4 +1,7 @@ %Error: t/t_semaphore.v:17:4: Can't find typedef: 'semaphore' 17 | semaphore s; | ^~~~~~~~~ +%Error: t/t_semaphore.v:18:4: Can't find typedef: 'semaphore' + 18 | semaphore s2; + | ^~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_semaphore.v b/test_regress/t/t_semaphore.v index 322a8541a..bc229ad75 100644 --- a/test_regress/t/t_semaphore.v +++ b/test_regress/t/t_semaphore.v @@ -13,8 +13,9 @@ // endclass module t(/*AUTOARG*/); - //From UVM: + // From UVM: semaphore s; + semaphore s2; int msg; initial begin @@ -30,6 +31,7 @@ module t(/*AUTOARG*/); s.put(2); if (s.try_get(2) <= 0) $stop; +`ifndef VERILATOR fork begin #10; // So later then get() starts below @@ -42,6 +44,10 @@ module t(/*AUTOARG*/); s.get(); end join +`endif + + s2 = new; + if (s2.try_get() != 0) $stop; $write("*-* All Finished *-*\n"); $finish; diff --git a/test_regress/t/t_semaphore_bad.out b/test_regress/t/t_semaphore_bad.out new file mode 100644 index 000000000..76d60e04d --- /dev/null +++ b/test_regress/t/t_semaphore_bad.out @@ -0,0 +1,7 @@ +%Error: t/t_semaphore.v:17:4: Can't find typedef: 'semaphore' + 17 | semaphore s; + | ^~~~~~~~~ +%Error: t/t_semaphore.v:18:4: Can't find typedef: 'semaphore' + 18 | semaphore s2; + | ^~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_semaphore_bad.pl b/test_regress/t/t_semaphore_bad.pl new file mode 100755 index 000000000..92483cce2 --- /dev/null +++ b/test_regress/t/t_semaphore_bad.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t_semaphore.v"); + +lint( + verilator_flags2 => ["--xml-only"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_semaphore_bad.v b/test_regress/t/t_semaphore_bad.v new file mode 100644 index 000000000..68e6ee38b --- /dev/null +++ b/test_regress/t/t_semaphore_bad.v @@ -0,0 +1,17 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + semaphore s; + + initial begin + s = new(4); + if (s.bad_method() != 0) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_strength_2_uneq_assign.out b/test_regress/t/t_strength_2_uneq_assign.out new file mode 100644 index 000000000..4235b8fb3 --- /dev/null +++ b/test_regress/t/t_strength_2_uneq_assign.out @@ -0,0 +1,10 @@ +%Error-UNSUPPORTED: t/t_strength_2_uneq_assign.v:10:30: Unsupported: Unable to resolve unequal strength specifier + : ... In instance t + 10 | assign (weak0, strong1) a = clk ? 'z : '0; + | ^ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_strength_2_uneq_assign.v:11:30: Unsupported: Unable to resolve unequal strength specifier + : ... In instance t + 11 | assign (strong0, pull1) a = 6'b110001; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_strength_2_uneq_assign.pl b/test_regress/t/t_strength_2_uneq_assign.pl new file mode 100755 index 000000000..19ba90d40 --- /dev/null +++ b/test_regress/t/t_strength_2_uneq_assign.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_strength_2_uneq_assign.v b/test_regress/t/t_strength_2_uneq_assign.v new file mode 100644 index 000000000..2c92a21b1 --- /dev/null +++ b/test_regress/t/t_strength_2_uneq_assign.v @@ -0,0 +1,19 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (clk); + input clk; + wire [5:0] a; + assign (weak0, strong1) a = clk ? 'z : '0; + assign (strong0, pull1) a = 6'b110001; + initial begin + if (a === 6'b110001) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule diff --git a/test_regress/t/t_strength_assignments_constants.pl b/test_regress/t/t_strength_assignments_constants.pl new file mode 100755 index 000000000..f5e338520 --- /dev/null +++ b/test_regress/t/t_strength_assignments_constants.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_strength_assignments_constants.v b/test_regress/t/t_strength_assignments_constants.v new file mode 100644 index 000000000..8344adbdd --- /dev/null +++ b/test_regress/t/t_strength_assignments_constants.v @@ -0,0 +1,38 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + wire a; + assign (weak0, weak1) a = 1; + assign (weak0, supply1) a = 1; + assign (strong0, strong1) a = 0; + + wire (weak0, weak1) b = 1; + assign (strong0, strong1) b = 0; + + wire [1:0] c; + assign (weak0, supply1) c = '1; + assign (supply0, pull1) c = '1; + assign (strong0, strong1) c = '0; + + supply0 d; + assign (strong0, strong1) d = 1; + + wire (supply0, supply1) e = 'z; + assign (weak0, weak1) e = 1; + + always begin + if (a && !b && c === '1 && !d && e) begin + $write("*-* All Finished *-*\n"); + $finish; + end + else begin + $write("Error: a = %b, b = %b, c = %b, d = %b, e = %b ", a, b, c, d, e); + $write("expected: a = 1, b = 0, c = 11, d = 0, e = 1\n"); + $stop; + end + end +endmodule diff --git a/test_regress/t/t_strength_bufif1.out b/test_regress/t/t_strength_bufif1.out new file mode 100644 index 000000000..0ac300369 --- /dev/null +++ b/test_regress/t/t_strength_bufif1.out @@ -0,0 +1,5 @@ +%Error-UNSUPPORTED: t/t_strength_bufif1.v:9:11: Unsupported: Strength specifier on this gate type + 9 | bufif1 (strong0, strong1) (a, 1'b1, 1'b1); + | ^ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_strength_bufif1.pl b/test_regress/t/t_strength_bufif1.pl new file mode 100755 index 000000000..35c0dfe5b --- /dev/null +++ b/test_regress/t/t_strength_bufif1.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +lint( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_strength_bufif1.v b/test_regress/t/t_strength_bufif1.v new file mode 100644 index 000000000..0a78b107c --- /dev/null +++ b/test_regress/t/t_strength_bufif1.v @@ -0,0 +1,17 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + wire a; + bufif1 (strong0, strong1) (a, 1'b1, 1'b1); + + always begin + if (a) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_strength_equal_strength.pl b/test_regress/t/t_strength_equal_strength.pl new file mode 100755 index 000000000..f5e338520 --- /dev/null +++ b/test_regress/t/t_strength_equal_strength.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_strength_equal_strength.v b/test_regress/t/t_strength_equal_strength.v new file mode 100644 index 000000000..fbbe8bdf1 --- /dev/null +++ b/test_regress/t/t_strength_equal_strength.v @@ -0,0 +1,48 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +interface inter (input logic cond, output wire a); + parameter W; + // Example: + wire (weak0, weak1) [W-1:0] b = '1; + assign (strong0, strong1) b = cond ? 'b0 : 'bz; + + assign a = b[10]; + +endinterface + +module t (clk1, clk2); + input wire clk1; + input wire clk2; + + wire (weak0, weak1) a = 0; + assign (supply0, supply1) a = 1'bz; + assign (pull0, pull1) a = 1; + + wire [2:0] b; + assign b = 3'b101; + assign (supply0, supply1) b = 3'b01z; + + wire c; + and (weak0, weak1) (c, clk1, clk2); + assign (strong0, strong1) c = 'z; + assign (pull0, pull1) c = 0; + + wire d; + inter #(.W(32)) i(.cond(1'b1), .a(d)); + + always begin + if (a === 1 && b === 3'b011 && c === 0 && d === 0) begin + $write("*-* All Finished *-*\n"); + $finish; + end + else begin + $write("Error: a = %b, b = %b, c = %b, d = %b", a, b, c, d); + $write("expected: a = %b, b = %b, c = %b, d = %b\n", clk1, 3'b011, 0, 0); + $stop; + end + end +endmodule diff --git a/test_regress/t/t_strength_highz.out b/test_regress/t/t_strength_highz.out new file mode 100644 index 000000000..06f32f6e9 --- /dev/null +++ b/test_regress/t/t_strength_highz.out @@ -0,0 +1,14 @@ +%Error-UNSUPPORTED: t/t_strength_highz.v:8:17: Unsupported: highz strength + 8 | wire (weak0, highz1) a = 1; + | ^~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_strength_highz.v:9:19: Unsupported: highz strength + 9 | wire (strong1, highz0) b = 0; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_strength_highz.v:10:10: Unsupported: highz strength + 10 | wire (highz0, pull1) c = 0; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_strength_highz.v:11:10: Unsupported: highz strength + 11 | wire (highz1, supply0) d = 1; + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_strength_highz.pl b/test_regress/t/t_strength_highz.pl new file mode 100755 index 000000000..48bf31461 --- /dev/null +++ b/test_regress/t/t_strength_highz.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +lint( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_strength_highz.v b/test_regress/t/t_strength_highz.v new file mode 100644 index 000000000..340723aba --- /dev/null +++ b/test_regress/t/t_strength_highz.v @@ -0,0 +1,19 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + wire (weak0, highz1) a = 1; + wire (strong1, highz0) b = 0; + wire (highz0, pull1) c = 0; + wire (highz1, supply0) d = 1; + + always begin + if (a === 1'bz && b === 1'bz && c === 1'bz && d === 1'bz) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_strength_strong1_strong1_bad.out b/test_regress/t/t_strength_strong1_strong1_bad.out new file mode 100644 index 000000000..b1e299714 --- /dev/null +++ b/test_regress/t/t_strength_strong1_strong1_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_strength_strong1_strong1_bad.v:8:19: syntax error, unexpected strong1 + 8 | wire (strong1, strong1) a = 1; + | ^~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_strength_strong1_strong1_bad.pl b/test_regress/t/t_strength_strong1_strong1_bad.pl new file mode 100755 index 000000000..19ba90d40 --- /dev/null +++ b/test_regress/t/t_strength_strong1_strong1_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_strength_strong1_strong1_bad.v b/test_regress/t/t_strength_strong1_strong1_bad.v new file mode 100644 index 000000000..ab84216cc --- /dev/null +++ b/test_regress/t/t_strength_strong1_strong1_bad.v @@ -0,0 +1,13 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + wire (strong1, strong1) a = 1; + initial begin + $stop; + end + +endmodule diff --git a/test_regress/t/t_strength_strongest_constant.pl b/test_regress/t/t_strength_strongest_constant.pl new file mode 100755 index 000000000..f5e338520 --- /dev/null +++ b/test_regress/t/t_strength_strongest_constant.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_strength_strongest_constant.v b/test_regress/t/t_strength_strongest_constant.v new file mode 100644 index 000000000..d8fec7098 --- /dev/null +++ b/test_regress/t/t_strength_strongest_constant.v @@ -0,0 +1,33 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (clk1, clk2); + input wire clk1; + input wire clk2; + + wire a; + nor (pull0, weak1) n1(a, 0, 0); + assign (strong0, weak1) a = 0; + + wire [1:0] b; + assign (weak0, supply1) b = '1; + assign b = clk1 ? '0 : 'z; + + wire c = 1; + assign (weak0, pull1) c = clk1 & clk2; + + always begin + if (!a && b === '1 && c) begin + $write("*-* All Finished *-*\n"); + $finish; + end + else begin + $write("Error: a = %b, b = %b, c = %b ", a, b, c); + $write("expected: a = 0, b = 11, c = 1\n"); + $stop; + end + end +endmodule diff --git a/test_regress/t/t_strength_strongest_non_tristate.pl b/test_regress/t/t_strength_strongest_non_tristate.pl new file mode 100755 index 000000000..f5e338520 --- /dev/null +++ b/test_regress/t/t_strength_strongest_non_tristate.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_strength_strongest_non_tristate.v b/test_regress/t/t_strength_strongest_non_tristate.v new file mode 100644 index 000000000..5c3c64c86 --- /dev/null +++ b/test_regress/t/t_strength_strongest_non_tristate.v @@ -0,0 +1,35 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (clk1, clk2); + input wire clk1; + input wire clk2; + + wire (weak0, weak1) a = 0; + assign (strong0, supply1) a = clk1; + assign (pull0, pull1) a = 1; + + wire b; + xor (strong0, strong1) (b, clk1, clk2); + and (weak0, pull1) (b, clk1, clk2); + + wire [7:0] c; + assign (supply0, strong1) c = clk1 ? '1 : '0; + assign (weak0, supply1) c = '0; + assign (weak0, pull1) c = 'z; + + always begin + if (a === clk1 && b === clk1 ^ clk2 && c[0] === clk1) begin + $write("*-* All Finished *-*\n"); + $finish; + end + else begin + $write("Error: a = %b, b = %b, c[0] = %b, ", a, b, c[0]); + $write("expected: a = %b, b = %b, c[0] = %b\n", clk1, clk1 ^ clk2, clk1); + $stop; + end + end +endmodule diff --git a/test_regress/t/t_trace_open_wrong_order.cpp b/test_regress/t/t_trace_open_wrong_order.cpp new file mode 100644 index 000000000..56dae22c3 --- /dev/null +++ b/test_regress/t/t_trace_open_wrong_order.cpp @@ -0,0 +1,25 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +// +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2010 by Yu-Sheng Lin. +// SPDX-License-Identifier: CC0-1.0 + +#include +#include + +#include "Vt_trace_open_wrong_order.h" +using namespace std; + +int main(int argc, char** argv) { + VerilatedContext ctx; + VerilatedVcdC tfp; + Vt_trace_open_wrong_order dut; + ctx.traceEverOn(true); + tfp.open(VL_STRINGIFY(TEST_OBJ_DIR) "/dump.vcd"); // Error! shall put to the next line! + dut.trace(&tfp, 99); // Error! + tfp.dump(0); + tfp.close(); + return 0; +} diff --git a/test_regress/t/t_trace_open_wrong_order.pl b/test_regress/t/t_trace_open_wrong_order.pl new file mode 100755 index 000000000..a7c8b6c51 --- /dev/null +++ b/test_regress/t/t_trace_open_wrong_order.pl @@ -0,0 +1,30 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Yu-Sheng Lin. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if ($Self->{vlt_all}) { + compile( + verilator_flags2 => ["--cc --trace --exe $Self->{t_dir}/$Self->{name}.cpp"], + make_top_shell => 0, + make_main => 0, + ); +} else { + compile( + ); +} + +execute( + fails => 1 + ); +file_grep($Self->{run_log_filename}, qr/::trace\(\)' shall not be called after 'VerilatedVcdC::open\(\)'/i); + +ok(1); +1; diff --git a/test_regress/t/t_trace_open_wrong_order.v b/test_regress/t/t_trace_open_wrong_order.v new file mode 100644 index 000000000..60a7504fd --- /dev/null +++ b/test_regress/t/t_trace_open_wrong_order.v @@ -0,0 +1,8 @@ +// DESCRIPTION: Verilator: Verilog dummy test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Yu-Sheng Lin. +// SPDX-License-Identifier: CC0-1.0 + +module t(input clk); +endmodule diff --git a/test_regress/t/t_trace_two_sc.cpp b/test_regress/t/t_trace_two_sc.cpp index 118a2d0a1..99f111fe4 100644 --- a/test_regress/t/t_trace_two_sc.cpp +++ b/test_regress/t/t_trace_two_sc.cpp @@ -21,6 +21,7 @@ // General headers #include "verilated.h" + #include "systemc.h" VM_PREFIX* ap; diff --git a/test_regress/t/t_var_sc_bv.cpp b/test_regress/t/t_var_sc_bv.cpp new file mode 100644 index 000000000..d8324bf2f --- /dev/null +++ b/test_regress/t/t_var_sc_bv.cpp @@ -0,0 +1,220 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +#include VM_PREFIX_INCLUDE + +VM_PREFIX* tb = nullptr; +bool pass = true; + +double sc_time_stamp() { return 0; } + +void compare_signals(const sc_signal>& ls, const sc_signal>& rs) { + if (ls.read() != rs.read()) { + pass &= false; + VL_PRINTF("%%Error: Data missmatch in signals %s and %s\n", ls.name(), rs.name()); + } +} + +void compareWls(int obits, WDataInP const lwp, WDataInP const rwp) { + const int words = VL_WORDS_I(obits); + bool same = true; + + for (int i = 0; (i < (words - 1)); ++i) { + if (lwp[i] != rwp[i]) { same = false; } + } + if ((lwp[words - 1] & VL_MASK_E(obits)) != (rwp[words - 1] & VL_MASK_E(obits))) { + same = false; + } + + if (!same) { + pass &= false; + VL_PRINTF("%%Error: There is a difference in VlWide variable %d bits wide\n", obits); + } +} + +// old macro which is correct but has MT issue with range +#define VL_ASSIGN_SBW_MT_ISSUE(obits, svar, rwp) \ + { \ + sc_biguint<(obits)> _butemp; \ + for (int i = 0; i < VL_WORDS_I(obits); ++i) { \ + int msb = ((i + 1) * VL_IDATASIZE) - 1; \ + msb = (msb >= (obits)) ? ((obits)-1) : msb; \ + _butemp.range(msb, i* VL_IDATASIZE) = (rwp)[i]; \ + } \ + (svar).write(_butemp); \ + } + +#ifdef SYSTEMC_VERSION +int sc_main(int, char**) +#else +int main() +#endif +{ + Verilated::debug(0); + tb = new VM_PREFIX("tb"); + + VlWide<8> /*255:0*/ input_var; + VlWide<8> /*255:0*/ out_var; + + // msb is always set to F not to be false positive on checking equality + input_var.m_storage[0] = 0xF2341234; + input_var.m_storage[1] = 0xFEADBEEF; + input_var.m_storage[2] = 0xF5A5A5A5; + input_var.m_storage[3] = 0xF1B2C3D4; + input_var.m_storage[4] = 0xFFFFFFFF; + input_var.m_storage[5] = 0xFAAABBBB; + input_var.m_storage[6] = 0xF000AAAA; + input_var.m_storage[7] = 0xF0101010; + +#ifdef SYSTEMC_VERSION + // clang-format off + sc_signal> SC_NAMED(i_29_s), SC_NAMED(i_29_old_s), SC_NAMED(o_29_s), SC_NAMED(o_29_old_s), + SC_NAMED(i_30_s), SC_NAMED(i_30_old_s), SC_NAMED(o_30_s), SC_NAMED(o_30_old_s), + SC_NAMED(i_31_s), SC_NAMED(i_31_old_s), SC_NAMED(o_31_s), SC_NAMED(o_31_old_s), + SC_NAMED(i_32_s), SC_NAMED(i_32_old_s), SC_NAMED(o_32_s), SC_NAMED(o_32_old_s), + SC_NAMED(i_59_s), SC_NAMED(i_59_old_s), SC_NAMED(o_59_s), SC_NAMED(o_59_old_s), + SC_NAMED(i_60_s), SC_NAMED(i_60_old_s), SC_NAMED(o_60_s), SC_NAMED(o_60_old_s), + SC_NAMED(i_62_s), SC_NAMED(i_62_old_s), SC_NAMED(o_62_s), SC_NAMED(o_62_old_s), + SC_NAMED(i_64_s), SC_NAMED(i_64_old_s), SC_NAMED(o_64_s), SC_NAMED(o_64_old_s), + SC_NAMED(i_119_s), SC_NAMED(i_119_old_s), SC_NAMED(o_119_s), SC_NAMED(o_119_old_s), + SC_NAMED(i_120_s), SC_NAMED(i_120_old_s), SC_NAMED(o_120_s), SC_NAMED(o_120_old_s), + SC_NAMED(i_121_s), SC_NAMED(i_121_old_s), SC_NAMED(o_121_s), SC_NAMED(o_121_old_s), + SC_NAMED(i_127_s), SC_NAMED(i_127_old_s), SC_NAMED(o_127_s), SC_NAMED(o_127_old_s), + SC_NAMED(i_128_s), SC_NAMED(i_128_old_s), SC_NAMED(o_128_s), SC_NAMED(o_128_old_s), + SC_NAMED(i_255_s), SC_NAMED(i_255_old_s), SC_NAMED(o_255_s), SC_NAMED(o_255_old_s), + SC_NAMED(i_256_s), SC_NAMED(i_256_old_s), SC_NAMED(o_256_s), SC_NAMED(o_256_old_s); + + + tb->i_29(i_29_s); tb->i_29_old(i_29_old_s); tb->o_29(o_29_s); tb->o_29_old(o_29_old_s); + tb->i_30(i_30_s); tb->i_30_old(i_30_old_s); tb->o_30(o_30_s); tb->o_30_old(o_30_old_s); + tb->i_31(i_31_s); tb->i_31_old(i_31_old_s); tb->o_31(o_31_s); tb->o_31_old(o_31_old_s); + tb->i_32(i_32_s); tb->i_32_old(i_32_old_s); tb->o_32(o_32_s); tb->o_32_old(o_32_old_s); + tb->i_59(i_59_s); tb->i_59_old(i_59_old_s); tb->o_59(o_59_s); tb->o_59_old(o_59_old_s); + tb->i_60(i_60_s); tb->i_60_old(i_60_old_s); tb->o_60(o_60_s); tb->o_60_old(o_60_old_s); + tb->i_62(i_62_s); tb->i_62_old(i_62_old_s); tb->o_62(o_62_s); tb->o_62_old(o_62_old_s); + tb->i_64(i_64_s); tb->i_64_old(i_64_old_s); tb->o_64(o_64_s); tb->o_64_old(o_64_old_s); + tb->i_119(i_119_s); tb->i_119_old(i_119_old_s); tb->o_119(o_119_s); tb->o_119_old(o_119_old_s); + tb->i_120(i_120_s); tb->i_120_old(i_120_old_s); tb->o_120(o_120_s); tb->o_120_old(o_120_old_s); + tb->i_121(i_121_s); tb->i_121_old(i_121_old_s); tb->o_121(o_121_s); tb->o_121_old(o_121_old_s); + tb->i_127(i_127_s); tb->i_127_old(i_127_old_s); tb->o_127(o_127_s); tb->o_127_old(o_127_old_s); + tb->i_128(i_128_s); tb->i_128_old(i_128_old_s); tb->o_128(o_128_s); tb->o_128_old(o_128_old_s); + tb->i_255(i_255_s); tb->i_255_old(i_255_old_s); tb->o_255(o_255_s); tb->o_255_old(o_255_old_s); + tb->i_256(i_256_s); tb->i_256_old(i_256_old_s); tb->o_256(o_256_s); tb->o_256_old(o_256_old_s); + + // clang-format on + +#endif + +// clang-format off +#ifdef SYSTEMC_VERSION + sc_start(1, SC_NS); +#else + tb->eval(); +#endif + // This testcase is testing multi-thread safe VL_ASSIGN_SBW and VL_ASSIGN_WSB macros. + // Testbench is assigning different number of bits from VlWide input_var variable to different inputs. + // Values around multiple of 30 (i.e. BITS_PER_DIGIT defined in SystemC sc_nbdefs.h) are tested with the special care, since + // it is the value by which the data_ptr of sc_biguint underlying data type is increased by (and not expected 32, as width of uint32_t). + // Correctness of the output is compared against the 'old' macro, which is correct but has multi-threaded issue since it's using range function. + // Second part is testing VL_ASSIGN_WSB in a reverse way, it is reading signals from the previous test, + // and comparing the output with (fraction) of VlWide input_var variable. + + // clang-format on + VL_ASSIGN_SBW(29, i_29_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(29, i_29_old_s, input_var); + VL_ASSIGN_SBW(30, i_30_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(30, i_30_old_s, input_var); + VL_ASSIGN_SBW(31, i_31_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(31, i_31_old_s, input_var); + VL_ASSIGN_SBW(32, i_32_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(32, i_32_old_s, input_var); + VL_ASSIGN_SBW(59, i_59_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(59, i_59_old_s, input_var); + VL_ASSIGN_SBW(60, i_60_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(60, i_60_old_s, input_var); + VL_ASSIGN_SBW(62, i_62_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(62, i_62_old_s, input_var); + VL_ASSIGN_SBW(64, i_64_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(64, i_64_old_s, input_var); + VL_ASSIGN_SBW(119, i_119_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(119, i_119_old_s, input_var); + VL_ASSIGN_SBW(120, i_120_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(120, i_120_old_s, input_var); + VL_ASSIGN_SBW(121, i_121_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(121, i_121_old_s, input_var); + VL_ASSIGN_SBW(127, i_127_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(127, i_127_old_s, input_var); + VL_ASSIGN_SBW(128, i_128_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(128, i_128_old_s, input_var); + VL_ASSIGN_SBW(255, i_255_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(255, i_255_old_s, input_var); + VL_ASSIGN_SBW(256, i_256_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(256, i_256_old_s, input_var); + +#ifdef SYSTEMC_VERSION + sc_start(1, SC_NS); +#else + tb->eval(); +#endif + compare_signals(o_29_s, o_29_old_s); + compare_signals(o_30_s, o_30_old_s); + compare_signals(o_31_s, o_31_old_s); + compare_signals(o_32_s, o_32_old_s); + compare_signals(o_59_s, o_59_old_s); + compare_signals(o_60_s, o_60_old_s); + compare_signals(o_62_s, o_62_old_s); + compare_signals(o_64_s, o_64_old_s); + compare_signals(o_119_s, o_119_old_s); + compare_signals(o_120_s, o_120_old_s); + compare_signals(o_121_s, o_121_old_s); + compare_signals(o_127_s, o_127_old_s); + compare_signals(o_128_s, o_128_old_s); + compare_signals(o_255_s, o_255_old_s); + compare_signals(o_256_s, o_256_old_s); + + //////////////////////////////// + + VL_ASSIGN_WSB(29, out_var, o_29_s); + compareWls(29, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(30, out_var, o_30_s); + compareWls(30, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(31, out_var, o_31_s); + compareWls(31, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(32, out_var, o_32_s); + compareWls(32, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(59, out_var, o_59_s); + compareWls(59, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(60, out_var, o_60_s); + compareWls(60, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(62, out_var, o_62_s); + compareWls(62, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(64, out_var, o_64_s); + compareWls(64, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(119, out_var, o_119_s); + compareWls(119, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(120, out_var, o_120_s); + compareWls(120, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(121, out_var, o_121_s); + compareWls(121, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(127, out_var, o_127_s); + compareWls(127, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(128, out_var, o_128_s); + compareWls(128, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(255, out_var, o_255_s); + compareWls(255, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(256, out_var, o_256_s); + compareWls(256, input_var.data(), out_var.data()); + + tb->final(); + VL_DO_DANGLING(delete tb, tb); + + if (pass) { + VL_PRINTF("*-* All Finished *-*\n"); + } else { + vl_fatal(__FILE__, __LINE__, "top", "Unexpected results from test\n"); + } + return 0; +} diff --git a/test_regress/t/t_var_sc_bv.pl b/test_regress/t/t_var_sc_bv.pl new file mode 100755 index 000000000..0091e49f0 --- /dev/null +++ b/test_regress/t/t_var_sc_bv.pl @@ -0,0 +1,24 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt_all => 1); + +compile( + make_top_shell => 0, + make_main => 0, + verilator_flags2 => ["--exe $Self->{t_dir}/t_var_sc_bv.cpp --sc -fno-inline"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_var_sc_bv.v b/test_regress/t/t_var_sc_bv.v new file mode 100644 index 000000000..d3164ee09 --- /dev/null +++ b/test_regress/t/t_var_sc_bv.v @@ -0,0 +1,246 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2008 by Lane Brooks. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Outputs + o_29,o_29_old, + o_30,o_30_old, + o_31,o_31_old, + o_32,o_32_old, + o_59,o_59_old, + o_60,o_60_old, + o_62,o_62_old, + o_64,o_64_old, + o_119,o_119_old, + o_120,o_120_old, + o_121,o_121_old, + o_127,o_127_old, + o_128,o_128_old, + o_255,o_255_old, + o_256,o_256_old, + // Inputs + i_29,i_29_old, + i_30,i_30_old, + i_31,i_31_old, + i_32,i_32_old, + i_59,i_59_old, + i_60,i_60_old, + i_62,i_62_old, + i_64,i_64_old, + i_119,i_119_old, + i_120,i_120_old, + i_121,i_121_old, + i_127,i_127_old, + i_128,i_128_old, + i_255,i_255_old, + i_256,i_256_old + ); + input [255:0] i_29; + output wire [255:0] o_29; + input [255:0] i_29_old; + output wire [255:0] o_29_old; + input [255:0] i_30; + output wire [255:0] o_30; + input [255:0] i_30_old; + output wire [255:0] o_30_old; + input [255:0] i_31; + output wire [255:0] o_31; + input [255:0] i_31_old; + output wire [255:0] o_31_old; + input [255:0] i_32; + output wire [255:0] o_32; + input [255:0] i_32_old; + output wire [255:0] o_32_old; + input [255:0] i_59; + output wire [255:0] o_59; + input [255:0] i_59_old; + output wire [255:0] o_59_old; + input [255:0] i_60; + output wire [255:0] o_60; + input [255:0] i_60_old; + output wire [255:0] o_60_old; + input [255:0] i_62; + output wire [255:0] o_62; + input [255:0] i_62_old; + output wire [255:0] o_62_old; + input [255:0] i_64; + output wire [255:0] o_64; + input [255:0] i_64_old; + output wire [255:0] o_64_old; + input [255:0] i_119; + output wire [255:0] o_119; + input [255:0] i_119_old; + output wire [255:0] o_119_old; + input [255:0] i_120; + output wire [255:0] o_120; + input [255:0] i_120_old; + output wire [255:0] o_120_old; + input [255:0] i_121; + output wire [255:0] o_121; + input [255:0] i_121_old; + output wire [255:0] o_121_old; + input [255:0] i_127; + output wire [255:0] o_127; + input [255:0] i_127_old; + output wire [255:0] o_127_old; + input [255:0] i_128; + output wire [255:0] o_128; + input [255:0] i_128_old; + output wire [255:0] o_128_old; + input [255:0] i_255; + output wire [255:0] o_255; + input [255:0] i_255_old; + output wire [255:0] o_255_old; + input [255:0] i_256; + output wire [255:0] o_256; + input [255:0] i_256_old; + output wire [255:0] o_256_old; + + sub sub (.*); +endmodule + +module sub (/*AUTOARG*/ + // Outputs + o_29,o_29_old, + o_30,o_30_old, + o_31,o_31_old, + o_32,o_32_old, + o_59,o_59_old, + o_60,o_60_old, + o_62,o_62_old, + o_64,o_64_old, + o_119,o_119_old, + o_120,o_120_old, + o_121,o_121_old, + o_127,o_127_old, + o_128,o_128_old, + o_255,o_255_old, + o_256,o_256_old, + // Inputs + i_29,i_29_old, + i_30,i_30_old, + i_31,i_31_old, + i_32,i_32_old, + i_59,i_59_old, + i_60,i_60_old, + i_62,i_62_old, + i_64,i_64_old, + i_119,i_119_old, + i_120,i_120_old, + i_121,i_121_old, + i_127,i_127_old, + i_128,i_128_old, + i_255,i_255_old, + i_256,i_256_old + ); + + input [255:0] i_29; + output wire [255:0] o_29; + input [255:0] i_29_old; + output wire [255:0] o_29_old; + input [255:0] i_30; + output wire [255:0] o_30; + input [255:0] i_30_old; + output wire [255:0] o_30_old; + input [255:0] i_31; + output wire [255:0] o_31; + input [255:0] i_31_old; + output wire [255:0] o_31_old; + input [255:0] i_32; + output wire [255:0] o_32; + input [255:0] i_32_old; + output wire [255:0] o_32_old; + input [255:0] i_59; + output wire [255:0] o_59; + input [255:0] i_59_old; + output wire [255:0] o_59_old; + input [255:0] i_60; + output wire [255:0] o_60; + input [255:0] i_60_old; + output wire [255:0] o_60_old; + input [255:0] i_62; + output wire [255:0] o_62; + input [255:0] i_62_old; + output wire [255:0] o_62_old; + input [255:0] i_64; + output wire [255:0] o_64; + input [255:0] i_64_old; + output wire [255:0] o_64_old; + input [255:0] i_119; + output wire [255:0] o_119; + input [255:0] i_119_old; + output wire [255:0] o_119_old; + input [255:0] i_120; + output wire [255:0] o_120; + input [255:0] i_120_old; + output wire [255:0] o_120_old; + input [255:0] i_121; + output wire [255:0] o_121; + input [255:0] i_121_old; + output wire [255:0] o_121_old; + input [255:0] i_127; + output wire [255:0] o_127; + input [255:0] i_127_old; + output wire [255:0] o_127_old; + input [255:0] i_128; + output wire [255:0] o_128; + input [255:0] i_128_old; + output wire [255:0] o_128_old; + input [255:0] i_255; + output wire [255:0] o_255; + input [255:0] i_255_old; + output wire [255:0] o_255_old; + input [255:0] i_256; + output wire [255:0] o_256; + input [255:0] i_256_old; + output wire [255:0] o_256_old; + + assign o_29 = i_29; + assign o_29_old = i_29_old; + + assign o_30 = i_30; + assign o_30_old = i_30_old; + + assign o_31 = i_31; + assign o_31_old = i_31_old; + + assign o_32 = i_32; + assign o_32_old = i_32_old; + + assign o_59 = i_59; + assign o_59_old = i_59_old; + + assign o_60 = i_60; + assign o_60_old = i_60_old; + + assign o_62 = i_62; + assign o_62_old = i_62_old; + + assign o_64 = i_64; + assign o_64_old = i_64_old; + + assign o_119 = i_119; + assign o_119_old = i_119_old; + + assign o_120 = i_120; + assign o_120_old = i_120_old; + + assign o_121 = i_121; + assign o_121_old = i_121_old; + + assign o_127 = i_127; + assign o_127_old = i_127_old; + + assign o_128 = i_128; + assign o_128_old = i_128_old; + + assign o_255 = i_255; + assign o_255_old = i_255_old; + + assign o_256 = i_256; + assign o_256_old = i_256_old; + +endmodule diff --git a/test_regress/t/t_vpi_get.cpp b/test_regress/t/t_vpi_get.cpp index fdd93ee01..898664841 100644 --- a/test_regress/t/t_vpi_get.cpp +++ b/test_regress/t/t_vpi_get.cpp @@ -71,7 +71,7 @@ } #define CHECK_RESULT_CSTR(got, exp) \ - if (strcmp((got), (exp))) { \ + if (std::strcmp((got), (exp))) { \ printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \ (got) ? (got) : "", (exp) ? (exp) : ""); \ return __LINE__; \ diff --git a/test_regress/t/t_vpi_module.cpp b/test_regress/t/t_vpi_module.cpp index 754cc2660..1c2de048c 100644 --- a/test_regress/t/t_vpi_module.cpp +++ b/test_regress/t/t_vpi_module.cpp @@ -61,7 +61,7 @@ } #define CHECK_RESULT_CSTR(got, exp) \ - if (strcmp((got), (exp))) { \ + if (std::strcmp((got), (exp))) { \ printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \ (got) ? (got) : "", (exp) ? (exp) : ""); \ return __LINE__; \ @@ -100,7 +100,7 @@ int mon_check() { CHECK_RESULT_NZ(t_name); // Icarus reports the top most module as "top" - if (strcmp(t_name, "top") == 0) { + if (std::strcmp(t_name, "top") == 0) { it = vpi_iterate(vpiModule, topmod); CHECK_RESULT_NZ(it); CHECK_RESULT(vpi_get(vpiType, it), vpiModule); @@ -129,7 +129,7 @@ int mon_check() { CHECK_RESULT_NZ(mod3); const char* mod_c_name = vpi_get_str(vpiName, mod3); - if (strcmp(mod_c_name, "mod_b") == 0) { + if (std::strcmp(mod_c_name, "mod_b") == 0) { // Full visibility in other simulators, skip mod_b TestVpiHandle mod4 = vpi_scan(it3); CHECK_RESULT_NZ(mod4); diff --git a/test_regress/t/t_vpi_param.cpp b/test_regress/t/t_vpi_param.cpp index 51415a38b..dcc4a7fb9 100644 --- a/test_regress/t/t_vpi_param.cpp +++ b/test_regress/t/t_vpi_param.cpp @@ -71,7 +71,7 @@ } #define CHECK_RESULT_CSTR(got, exp) \ - if (strcmp((got), (exp))) { \ + if (std::strcmp((got), (exp))) { \ printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \ (got) ? (got) : "", (exp) ? (exp) : ""); \ return __LINE__; \ diff --git a/test_regress/t/t_vpi_unimpl.cpp b/test_regress/t/t_vpi_unimpl.cpp index 549d66e1e..e91515a6e 100644 --- a/test_regress/t/t_vpi_unimpl.cpp +++ b/test_regress/t/t_vpi_unimpl.cpp @@ -66,7 +66,7 @@ unsigned int callback_count = 0; } #define CHECK_RESULT_CSTR(got, exp) \ - if (strcmp((got), (exp))) { \ + if (std::strcmp((got), (exp))) { \ printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \ (got) ? (got) : "", (exp) ? (exp) : ""); \ return __LINE__; \ diff --git a/test_regress/t/t_vpi_var.cpp b/test_regress/t/t_vpi_var.cpp index b8186c281..1c5c76f50 100644 --- a/test_regress/t/t_vpi_var.cpp +++ b/test_regress/t/t_vpi_var.cpp @@ -90,7 +90,7 @@ bool verbose = false; } #define CHECK_RESULT_CSTR(got, exp) \ - if (strcmp((got), (exp))) { \ + if (std::strcmp((got), (exp))) { \ printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \ ((got) != NULL) ? (got) : "", ((exp) != NULL) ? (exp) : ""); \ return __LINE__; \ @@ -117,7 +117,7 @@ int _mon_check_mcd() { } status = vpi_mcd_printf(mcd, (PLI_BYTE8*)"hello %s", "vpi_mcd_printf"); - CHECK_RESULT(status, strlen("hello vpi_mcd_printf")); + CHECK_RESULT(status, std::strlen("hello vpi_mcd_printf")); status = vpi_mcd_printf(0, (PLI_BYTE8*)"empty"); CHECK_RESULT(status, 0); @@ -634,7 +634,7 @@ int _mon_check_vlog_info() { CHECK_RESULT_Z(vlog_info.argv[4]); if (TestSimulator::is_verilator()) { CHECK_RESULT_CSTR(vlog_info.product, "Verilator"); - CHECK_RESULT(strlen(vlog_info.version) > 0, 1); + CHECK_RESULT(std::strlen(vlog_info.version) > 0, 1); } return 0; }