Merge from master for release.

This commit is contained in:
Wilson Snyder 2022-10-01 08:33:50 -04:00
commit 04fff7ebd8
283 changed files with 17784 additions and 15562 deletions

View File

@ -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

View File

@ -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: |

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
\#*
.#*
.gdb_history
.nfs*
*~
*.tidy

30
Changes
View File

@ -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]

View File

@ -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)

View File

@ -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
============================

View File

@ -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 <filename> Override Verilator binary
--build Build model executable/library after Verilation
--build-dep-bin <filename> Override build dependency Verilator binary
--build-jobs <jobs> Parallelism for --build
--cc Create C++ output
--cdc Clock domain crossing analysis
-CFLAGS <flags> C++ compiler arguments for makefile
@ -308,10 +309,13 @@ detailed descriptions of these arguments.
+define+<var>=<value> 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 <level> Enable dumping .tree files at a level
--dump-treei-<srcfile> <level> Enable dumping .tree file at a source file at a level
--dump-<srcfile> Enable dumping everything in source file
--dumpi-graph <level> Enable dumping V3Graphs to .dot files at level
--dumpi-tree <level> Enable dumping Ast .tree files at level
--dumpi-<srcfile> <level> Enable dumping everything in source file at level
-E Preprocess, but do not compile
--error-limit <value> Abort after this number of errors
--exe Link to create executable
@ -334,7 +338,7 @@ detailed descriptions of these arguments.
+incdir+<dir> Directory to search for includes
--inline-mult <value> Tune module inlining
--instr-count-dpi <value> Assumed dynamic instruction count of DPI imports
-j <jobs> Parallelism for --build
-j <jobs> Parallelism for --build (alias to --build-jobs)
--l2-name <value> Verilog scope name of the top module
--language <lang> Default language standard to parse
-LDFLAGS <flags> Linker pre-object arguments for makefile
@ -343,6 +347,7 @@ detailed descriptions of these arguments.
--lint-only Lint, but do not make output
--make <build-tool> Generate scripts for specified build tool
-MAKEFLAGS <flags> Arguments to pass to make during --build
--main Generate C++ main() file
--max-num-width <value> Maximum number width (default: 64K)
--Mdir <directory> Name of output object directory
--MMD Create .d dependency files
@ -354,6 +359,7 @@ detailed descriptions of these arguments.
-O<optimization-letter> Selectable optimizations
-o <executable> Name of final executable
--no-order-clock-delay Disable ordering clock enable assignments
--no-verilate Skip Verilation, only compile previously Verilated code
--output-split <statements> Split .cpp files into pieces
--output-split-cfuncs <statements> Split model functions
--output-split-ctrace <statements> Split tracing functions

View File

@ -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']

View File

@ -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']:

View File

@ -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;
}

View File

@ -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 \

View File

@ -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

View File

@ -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 \

View File

@ -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])

View File

@ -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

View File

@ -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,

View File

@ -115,13 +115,6 @@ Summary:
Using this argument will likely cause incorrect simulation.
.. option:: --bin <filename>
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 <filename>
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 [<value>]
Specify the level of parallelism for :vlopt:`--build`. If zero, uses the
number of threads in the current hardware. Otherwise, the <value> 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 <level>
.. option:: --dump-treei-<srcfile> <level>
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-<srcfile>
Rarely needed - for developer use. Enable all dumping in the given
source file at level 3.
.. option:: --dumpi-graph <level>
Rarely needed - for developer use. Set internal V3Graph dumping level
globally to the specified value.
.. option:: --dumpi-tree <level>
Rarely needed - for developer use. Set internal Ast dumping level
globally to the specified value.
.. option:: --dumpi-<srcfile> <level>
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-<srcfile>`. 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 [<value>]
Specify the level of parallelism for :vlopt:`--build`. The <value> must
be a positive integer specifying the maximum number of parallel build
jobs, or can be omitted. When <value> 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 <value> must be a positive
integer specifying the maximum number of parallel build jobs.
.. option:: --l2-name <value>
@ -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 <value>
Set the maximum number literal width (e.g. in 1024'd22 this it the

View File

@ -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

View File

@ -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:

View File

@ -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 <keywords> := <description>``,
where ``<keywords>`` determines what is being defined, and ``<description>`` is
a ``<keywords>`` dependent description of the definition. The list of
``@astgen`` directives is as follows:
``op<N>`` 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
``<description>`` field is ``<identifier> : <type>``, where ``<identifier>``
will be used as the base name of the generated operand accessors, and
``<type>`` 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[<AstNode sub-class>]``. 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 ``<identifier>``. For list type children, the getter is ``<identifier>``,
and instead of the setter, there an ``add<Identifier>`` method is generated
that appends new nodes (or lists of nodes) to the child list.
``alias op<N>`` operand alias directives
""""""""""""""""""""""""""""""""""""""""
If a super-class already defined a name and type for a child node using the
``op<N>`` 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<N> := <identifier>`` where
``<identifier>`` is the new name. ``op<N>`` 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_<newtestcase>.pl --debug" and it'll
probably fail but you'll see a

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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 = {}

View File

@ -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='"<<tmpp<<"'\n");
}
static inline char* _vl_vsss_read_bin(FILE* fp, int& floc, const WDataInP fromp,
const std::string& fstr, char* beginp, std::size_t n,
const bool inhibit = false) {
static char* _vl_vsss_read_bin(FILE* fp, int& floc, const WDataInP fromp, const std::string& fstr,
char* beginp, std::size_t n, const bool inhibit = false) {
// Variant of _vl_vsss_read_str using the same underlying I/O functions but optimized
// specifically for block reads of N bytes (read operations are not demarcated by
// whitespace). In the fp case, except descriptor to have been opened in binary mode.
@ -1073,12 +1071,11 @@ static inline char* _vl_vsss_read_bin(FILE* fp, int& floc, const WDataInP fromp,
}
return beginp;
}
static inline void _vl_vsss_setbit(WDataOutP owp, int obits, int lsb, int nbits,
IData ld) VL_MT_SAFE {
static void _vl_vsss_setbit(WDataOutP owp, int obits, int lsb, int nbits, IData ld) VL_MT_SAFE {
for (; nbits && lsb < obits; nbits--, lsb++, ld >>= 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<int>(posend) - 1;

View File

@ -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

View File

@ -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");

View File

@ -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

View File

@ -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

View File

@ -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<IData, EData>::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); \
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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 <bool SpinWait>
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];

View File

@ -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<QData*>(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<double*>(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<QData*>(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

View File

@ -551,15 +551,15 @@ template <>
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::runOffloadedCallbacks(
const std::vector<CallbackRecord>& 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<OffloadBuffer*>(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<VL_SUB_T, VL_BUF_T>::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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -96,7 +96,7 @@ public:
*(reinterpret_cast<uint32_t*>(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<uint8_t*>(obj)) - 8;
if (VL_UNLIKELY(*(reinterpret_cast<uint32_t*>(oldp)) != activeMagic())) {
VL_FATAL_MT(__FILE__, __LINE__, "",
@ -114,7 +114,7 @@ public:
static VerilatedVpio* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpio*>(reinterpret_cast<VerilatedVpio*>(h));
}
inline vpiHandle castVpiHandle() { return reinterpret_cast<vpiHandle>(this); }
vpiHandle castVpiHandle() { return reinterpret_cast<vpiHandle>(this); }
// ACCESSORS
virtual const char* name() const { return "<null>"; }
virtual const char* fullname() const { return "<null>"; }

View File

@ -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 <class T>
T const& as_const(T& v) {
return v;
}
}; // namespace vlstd
//=========================================================================

View File

@ -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\(\)')

View File

@ -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

View File

@ -38,6 +38,8 @@
#include <unordered_map>
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<AstVarRef*> m_outputs; // Vector of lvalues encountered on this pass
VL_DEBUG_FUNC; // Declare debug()
static LatchDetectGraphVertex* castVertexp(void* vertexp) {
return reinterpret_cast<LatchDetectGraphVertex*>(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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -28,6 +28,8 @@
#include <iomanip>
#include <memory>
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, AstNode>(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 <e" << std::dec << editCountLast();
*logsp << "> to <e" << std::dec << editCountGbl() << ">\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<AstNode*>(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());
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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<uint32_t>(left)});
rightp(new AstConst{fl, static_cast<uint32_t>(right)});
}
AstRange::AstRange(FileLine* fl, const VNumRange& range)
: ASTGEN_SUPER_Range(fl) {
leftp(new AstConst{fl, static_cast<uint32_t>(range.left())});
rightp(new AstConst{fl, static_cast<uint32_t>(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

1256
src/V3AstNodeDType.h Normal file

File diff suppressed because it is too large Load Diff

4287
src/V3AstNodeMath.h Normal file

File diff suppressed because it is too large Load Diff

4133
src/V3AstNodeOther.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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 <iomanip>
#include <iterator>
@ -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
<< " <e" << std::dec << editCount() << ((editCount() >= 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<const void*>(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() : "<unlinked>"; }
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<const void*>(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<int>(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<const AstNodeArrayDType*>(samep);
if (!asamep->subDTypep()) return false;
return (subDTypep() == asamep->subDTypep());
}
bool AstWildcardArrayDType::similarDType(AstNodeDType* samep) const {
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(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<const AstNodeArrayDType*>(samep);
if (!asamep->subDTypep()) return false;
return (subDTypep() == asamep->subDTypep());
}
bool AstUnsizedArrayDType::similarDType(AstNodeDType* samep) const {
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(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<const AstVarRef*>(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() << "]";

File diff suppressed because it is too large Load Diff

View File

@ -35,7 +35,7 @@ class AstUserAllocatorBase VL_NOT_FINAL {
private:
std::vector<T_Data*> 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<T_Data*>();
@ -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});
}
}

View File

@ -35,6 +35,8 @@
#include <algorithm>
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);
}

View File

@ -33,6 +33,8 @@
#include <map>
VL_DEFINE_DEBUG_FUNCTIONS;
//######################################################################
// Branch state, as a visitor of each AstNode
@ -49,7 +51,6 @@ private:
std::vector<AstCFunc*> 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;
};
//######################################################################

View File

@ -36,6 +36,8 @@
#include <unordered_map>
#include <unordered_set>
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;
};
//######################################################################

View File

@ -35,6 +35,8 @@
#include <algorithm>
#include <list>
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);
}
}
}

View File

@ -32,6 +32,8 @@
#include <set>
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);
}

View File

@ -45,6 +45,8 @@
#include <algorithm>
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<AstNode*, 1 << CASE_OVERLAP_WIDTH> 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);

View File

@ -47,6 +47,8 @@
#include <algorithm>
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);
}

View File

@ -38,13 +38,14 @@
#include <iomanip>
#include <memory>
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);
}
};

View File

@ -36,6 +36,8 @@
#include <algorithm>
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);
}

View File

@ -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<std::pair<AstNode*, AstNodeModule*>> 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);
}

View File

@ -33,6 +33,8 @@
#include <algorithm>
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);
}

View File

@ -37,6 +37,8 @@
#include <algorithm>
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<AstVarScope*>(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);
}

View File

@ -33,6 +33,8 @@
#include <list>
#include <vector>
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<AstCFunc*>& 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);
}

View File

@ -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);
}

View File

@ -27,6 +27,8 @@
#include <string>
#include <unordered_map>
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);

View File

@ -37,6 +37,8 @@
#include <memory>
#include <type_traits>
VL_DEFINE_DEBUG_FUNCTIONS;
//######################################################################
// Utilities
@ -350,7 +352,6 @@ class ConstBitOpTreeVisitor final : public VNVisitor {
std::vector<std::unique_ptr<VarInfo>> 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<AstNodeCond*>(
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<AstNodeCond*>(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<<endl; nodep->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) {

View File

@ -35,6 +35,8 @@
#include <map>
#include <unordered_map>
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<AstNode, AstNode>(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);
}

View File

@ -28,6 +28,8 @@
#include <vector>
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);
}

View File

@ -44,6 +44,8 @@
#include <map>
#include <vector>
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);
}

View File

@ -61,6 +61,8 @@
#include <deque>
#include <map>
VL_DEFINE_DEBUG_FUNCTIONS;
//######################################################################
// Delayed state, as a visitor of each AstNode
@ -102,7 +104,6 @@ private:
std::unordered_map<const AstVarScope*, int> 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);
}

View File

@ -34,6 +34,8 @@
#include <algorithm>
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);
}

View File

@ -31,6 +31,8 @@
#include <algorithm>
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);
}

View File

@ -33,6 +33,8 @@
#include <map>
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);
}

View File

@ -28,6 +28,8 @@
#include <map>
#include <memory>
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);
}

View File

@ -59,7 +59,6 @@ public:
}
// METHODS
VL_DEBUG_FUNC; // Declare debug()
// Expose minimal set of superclass interface
using Super::begin;

View File

@ -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;
}

View File

@ -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

View File

@ -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
};

View File

@ -27,6 +27,8 @@
#include <algorithm>
#include <cinttypes>
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);
}

View File

@ -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<string> 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<AstNode*> 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<AstNodeSimpleText*>(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<AstNodeUniop*>(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<int>(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

View File

@ -24,12 +24,13 @@
#include <algorithm>
#include <vector>
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); }

View File

@ -28,6 +28,8 @@
#include <set>
#include <vector>
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<string>* 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<AstCFile*>& m_cfilesr; // cfiles generated by this emit
// METHODS
void openNextOutputFile(const std::set<string>& 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<AstCFile*>& 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<AstCFile*>& 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<AstNode*, int> m_enumNumMap; // EnumDType to enumeration number
std::deque<AstCFile*>& 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<AstCFile*>& 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<AstCFile*>& 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<std::deque<AstCFile*>> 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);
}
}

View File

@ -24,6 +24,8 @@
#include <map>
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); }

View File

@ -25,6 +25,8 @@
#include <map>
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

View File

@ -26,13 +26,14 @@
#include <memory>
//######################################################################
// Emit statements
VL_DEFINE_DEBUG_FUNCTIONS;
// ######################################################################
// Emit statements
class CMakeEmitter final {
// METHODS
VL_DEBUG_FUNC; // Declare debug()
// STATIC FUNCTIONS

View File

@ -26,6 +26,8 @@
#include <functional>
#include <vector>
VL_DEFINE_DEBUG_FUNCTIONS;
class EmitCModel final : public EmitCFunc {
// TYPES
using CFuncVector = std::vector<const AstCFunc*>;
@ -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<bool(const AstCFunc*)> 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);

View File

@ -27,6 +27,8 @@
#include <map>
#include <vector>
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 "<<nodep->name()<<" sp "<<nodep->scopePrettySymName()
// <<" ss"<<name<<endl);
@ -337,19 +339,19 @@ class EmitCSyms final : EmitCBaseVisitor {
}
}
}
virtual void visit(AstVar* nodep) override {
void visit(AstVar* nodep) override {
nameCheck(nodep);
iterateChildren(nodep);
if (nodep->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)

View File

@ -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()
};
//######################################################################

View File

@ -26,6 +26,8 @@
#include <map>
#include <vector>
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<AstNodeSimpleText*>(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<AstNode*>(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<AstNode*>(nodep));
}
virtual ~EmitVPrefixedVisitor() override = default;
~EmitVPrefixedVisitor() override = default;
};
//######################################################################

View File

@ -26,6 +26,8 @@
#include <map>
#include <vector>
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("</if>\n");
}
virtual void visit(AstWhile* nodep) override {
void visit(AstWhile* nodep) override {
outputTag(nodep, "while");
puts(">\n");
puts("<begin>\n");
@ -150,19 +151,19 @@ class EmitXmlFileVisitor final : public VNVisitor {
}
puts("</while>\n");
}
virtual void visit(AstNetlist* nodep) override {
void visit(AstNetlist* nodep) override {
puts("<netlist>\n");
iterateChildren(nodep);
puts("</netlist>\n");
}
virtual void visit(AstConstPool* nodep) override {
void visit(AstConstPool* nodep) override {
if (!v3Global.opt.xmlOnly()) {
puts("<constpool>\n");
iterateChildren(nodep);
puts("</constpool>\n");
}
}
virtual void visit(AstInitArray* nodep) override {
void visit(AstInitArray* nodep) override {
puts("<initarray>\n");
const auto& mapr = nodep->map();
for (const auto& itr : mapr) {
@ -174,7 +175,7 @@ class EmitXmlFileVisitor final : public VNVisitor {
}
puts("</initarray>\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<FileLine*> 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 << "</module_files>\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 << "<cells>\n";
@ -402,7 +401,7 @@ private:
m_os << "</cells>\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 << "<cell " << nodep->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;
};
//######################################################################

View File

@ -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();

View File

@ -26,6 +26,7 @@
#include <array>
#include <bitset>
#include <cassert>
#include <cctype>
#include <deque>
#include <map>
#include <set>
@ -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<en>(_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-<srcfile> 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<int>(debugLevel); \
level = static_cast<int>(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<int>(dumpLevel); \
level = static_cast<int>(dumpLevel); \
} \
return level; \
} \
static_assert(true, "")
// Define debug*() and dump*() routines. This needs to be added to every compilation unit so that
// --debugi-<tag/srcfile> and --dumpi-<tag/srcfile> 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, "")
//----------------------------------------------------------------------

View File

@ -37,6 +37,8 @@
#include <algorithm>
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);
}

View File

@ -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<std::ofstream> 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<string> V3FileDependImp::getAllDeps() const {
std::vector<string> V3FileDependImp::getAllDeps() const {
std::vector<string> r;
for (const auto& itr : m_filenameList) {
if (!itr.target() && itr.exists()) r.push_back(itr.filename());
@ -179,7 +181,7 @@ inline std::vector<string> 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<std::ofstream> 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<std::ifstream> 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<char*>(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] << "->"

View File

@ -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("<?xml version=\"1.0\" ?>\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); }

Some files were not shown because too many files have changed in this diff Show More