Merge from master for release.

This commit is contained in:
Wilson Snyder 2021-12-05 11:15:32 -05:00
commit 141c5da3f9
434 changed files with 14072 additions and 6923 deletions

View File

@ -13,4 +13,6 @@ Can you attach an example that shows the issue? (Must be openly licensed, ideal
What 'verilator --version' are you using? Did you try it with the git master version?
What OS and distribution are you using?
Would you be willing to try to fix Verilator yourself with assistance?

1
.gitignore vendored
View File

@ -39,3 +39,4 @@ verilator-config-version.cmake
**/__pycache__/*
**/_build/*
**/obj_dir/*
/.vscode/

35
Changes
View File

@ -8,10 +8,45 @@ The changes in each Verilator version are described below. The
contributors that suggested a given feature are shown in []. Thanks!
Verilator 4.216 2021-12-05
==========================
**Major:**
* Add --lib-create, similar to --protect-lib but without protections.
* Support tracing through --hierarchical/--lib-create libraries (#3200).
**Minor:**
* Internal code cleanups and improvements. [Geza Lore]
* Improve --thread verilation-time performance.
* Support task name in $display %m (#3211). [Julie Schwartz]
* Make 'bit', 'logic' and 'time' types unsigned by default. [Geza Lore]
* Optimize $random concatenates/selects (#3114).
* Fix array method names with parenthesis (#3181) (#3183). [Teng Huang]
* Fix split_var assign merging (#3177) (#3179). [Yutetsu TAKATSUKASA]
* Fix wrong bit op tree optimization (#3185). [Yutetsu TAKATSUKASA]
* Fix some SliceSels not being constants (#3186) (#3218). [Michaël Lefebvre]
* Fix nested generate if genblk naming (#3189). [yanx21]
* Fix hang on recursive definition error (#3199). [Jonathan Kimmitt]
* Fix display of signed without format (#3204). [Julie Schwartz]
* Fix display of empty string constant (#3207) (#3215). [Julie Schwartz]
* Fix incorrect width after and-or optimization (#3208). [Julie Schwartz]
* Fix $fopen etc on integer arrays (#3214). [adrienlemasle]
* Fix $size on dynamic strings (#3216).
* Fix %0 format on $value$plusargs (#3217).
* Fix timescale portability on Arm64 (#3222).
Verilator 4.214 2021-10-17
==========================
**Major:**
* Add profile-guided optmization of mtasks (#3150).
**Minor:**
* Verilator_gantt has removed the ASCII graphics, use the VCD output instead.
* Verilator_gantt now shows the predicted mtask times, eval times, and additional statistics.
* Verilator_gantt data files now include processor information, to allow later processing.

View File

@ -336,6 +336,7 @@ detailed descriptions of these arguments.
-LDFLAGS <flags> Linker pre-object arguments for makefile
--l2-name <value> Verilog scope name of the top module
--language <lang> Default language standard to parse
--lib-create <name> Create a DPI library
+libext+<ext>+[ext]... Extensions for finding modules
--lint-only Lint, but do not make output
-MAKEFLAGS <flags> Arguments to pass to make during --build

View File

@ -7,7 +7,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[4.214 2021-10-17],
AC_INIT([Verilator],[4.216 2021-12-05],
[https://verilator.org],
[verilator],[https://verilator.org])
# When releasing, also update header of Changes file

View File

@ -45,6 +45,7 @@ John Coiner
John Demme
Jonathan Drolet
Josh Redford
Julie Schwartz
Julien Margetts
Kaleb Barrett
Kanad Kanhere
@ -63,6 +64,7 @@ Marshal Qiao
Martin Schmidt
Matthew Ballance
Michael Killough
Michaël Lefebvre
Mike Popoloski
Miodrag Milanović
Morten Borup Petersen
@ -88,6 +90,7 @@ Sergi Granell
Stefan Wallentowitz
Stephen Henry
Steven Hugg
Teng Huang
Tim Snyder
Tobias Rosenkranz
Tobias Wölfel

View File

@ -9,7 +9,7 @@ The following deprecated items are scheduled for future removal:
C++11 compiler support
Verilator currently requires C++11 or newer compilers. Verilator will
require C++14 or newer compilers for both compiling Verilator and
compiling Verilated models no sooner than January 2022.
compiling Verilated models no sooner than January 2023.
Verilated_heavy.h
The legacy "verilated_heavy.h" include was replaced with just including

View File

@ -158,41 +158,26 @@ Summary:
.. option:: --clk <signal-name>
Sometimes it is quite difficult for Verilator to distinguish clock
signals from other data signals. Occasionally the clock signals can end
up in the checking list of signals which determines if further
evaluation is needed. This will heavily degrade the performance of a
Verilated model.
With :vlopt:`--clk`, the specified signal-name is taken as a root clock
into the model, then Verilator will mark the signal as clocker and
propagate the clocker attribute automatically to other signals derived
from that. In this way, Verilator will try to avoid taking the clocker
signal into checking list.
into the model; Verilator will mark the signal as clocker and
propagate the clocker attribute automatically to other signals downstream in
that clock tree.
Note signal-name is specified by the RTL hierarchy path. For example,
v.foo.bar. If the signal is the input to top-module, the directly the
signal name. If you find it difficult to find the exact name, try to use
a :option:`/*verilator&32;clocker*/` metacomment in RTL file to mark the
The provided signal-name is specified using a RTL hierarchy path. For
example, v.foo.bar. If the signal is the input to top-module, then
directly provide the signal name. Alternatively, use a
:option:`/*verilator&32;clocker*/` metacomment in RTL file to mark the
signal directly.
If clock signals are assigned to vectors and then later used
individually, Verilator will attempt to decompose the vector and connect
the single-bit clock signals directly. This should be transparent to
the user.
If clock signals are assigned to vectors and then later used as
individual bits, Verilator will attempt to decompose the vector and
connect the single-bit clock signals.
.. option:: --make <build-tool>
Generates a script for the specified build tool.
Supported values are ``gmake`` for GNU Make and ``cmake`` for CMake.
Both can be specified together. If no build tool is specified, gmake is
assumed. The executable of gmake can be configured via environment
variable "MAKE".
When using :vlopt:`--build` Verilator takes over the responsibility of
building the model library/executable. For this reason :option:`--make`
cannot be specified when using :vlopt:`--build`.
The clocker attribute is useful in cases where Verilator does not
properly distinguish clock signals from other data signals. Using
clocker will cause the signal indicated to be considered a clock, and
remove it from the combinatorial logic reevaluation checking code. This
may greatly improve performance.
.. option:: --compiler <compiler-name>
@ -590,6 +575,23 @@ Summary:
"+libext+" is fairly standard across Verilog tools. Defaults to
".v+.sv".
.. option:: --lib-create <name>
Produces C++, Verilog wrappers and a Makefile which can in turn produce
a DPI library which can be used by Verilator or other simulators along
with the corresponding Verilog wrapper. The Makefile will build both a
static and dynamic version of the library named :file:`lib<name>.a` and
:file:`lib<name>.so` respectively. This is done because some simulators
require a dynamic library, but the static library is arguably easier to
use if possible. :vlopt:`--protect-lib` implies :vlopt:`--protect-ids`.
When using :vlopt:`--lib-create` it is advised to also use
:vlopt:`--timescale-override /1fs <--timescale-override>` to ensure the
model has a time resolution that is always compatible with the time
precision of the upper instantiating module.
See also :vlopt:`--protect-lib`.
.. option:: --lint-only
Check the files for lint violations only, do not create any other
@ -601,6 +603,19 @@ Summary:
If the design is not to be completely Verilated see also the
:vlopt:`--bbox-sys` and :vlopt:`--bbox-unsup` options.
.. option:: --make <build-tool>
Generates a script for the specified build tool.
Supported values are ``gmake`` for GNU Make and ``cmake`` for CMake.
Both can be specified together. If no build tool is specified, gmake is
assumed. The executable of gmake can be configured via environment
variable "MAKE".
When using :vlopt:`--build` Verilator takes over the responsibility of
building the model library/executable. For this reason :option:`--make`
cannot be specified when using :vlopt:`--build`.
.. option:: -MAKEFLAGS <string>
When using :vlopt:`--build`, add the specified argument to the invoked
@ -874,24 +889,15 @@ Summary:
.. option:: --protect-lib <name>
Produces C++, Verilog wrappers and a Makefile which can in turn produce
a DPI library which can be used by Verilator or other simulators along
with the corresponding Verilog wrapper. The Makefile will build both a
static and dynamic version of the library named :file:`lib<name>.a` and
:file:`lib<name>.so` respectively. This is done because some simulators
require a dynamic library, but the static library is arguably easier to
use if possible. :vlopt:`--protect-lib` implies :vlopt:`--protect-ids`.
Produces a DPI library similar to :vlopt:`--lib-create`, but hides
internal design details. :vlopt:`--protect-lib` implies
:vlopt:`--protect-ids`, and :vlopt:`--lib-create`.
This allows for the secure delivery of sensitive IP without the need for
encrypted RTL (i.e. IEEE P1735). See :file:`examples/make_protect_lib`
in the distribution for a demonstration of how to build and use the DPI
library.
When using :vlopt:`--protect-lib` it is advised to also use
:vlopt:`--timescale-override /1fs <--timescale-override>` to ensure the
model has a time resolution that is always compatible with the time
precision of the upper instantiating module.
.. option:: --private
Opposite of :vlopt:`--public`. Is the default; this option exists for
@ -1167,9 +1173,9 @@ Summary:
.. option:: --trace-underscore
Enable tracing of signals that start with an underscore. Normally, these
signals are not output during tracing. See also
:vlopt:`--coverage-underscore` option.
Enable tracing of signals or modules that start with an
underscore. Normally, these signals are not output during tracing. See
also :vlopt:`--coverage-underscore` option.
.. option:: -U<var>
@ -1506,9 +1512,9 @@ The grammar of configuration commands is as follows:
.. option:: no_clocker -module "<modulename>" [-function "<funcname>"] -var "<signame>"
Indicate the signal is used as clock or not. This information is used by
Verilator to mark the signal as clocker and propagate the clocker
attribute automatically to derived signals. See :vlopt:`--clk`.
Indicates that the signal is used as clock or not. This information is
used by Verilator to mark the signal and any derrived signals as
clocker. See :vlopt:`--clk`.
Same as :option:`/*verilator&32;clocker*/` metacomment.

View File

@ -48,6 +48,14 @@ or "`ifdef`"'s may break other tools.
Verilog functions where the variable is flattened out, and also enable
other optimizations.
Verilator does not use any text inside the quotes for
ordering/scheduling. If you need the $c to be called at a specific
time, e.g. when a variable changes, then the $c must be under an
appropriate sensitivity statement, e.g. :code:`always @(posedge clk)
$c("func()")` to call it on every edge, or e.g. :code:`always @*
c("func(",a,")")` to call it when :code:`a` changes (the latter working
because :code:`a` is outside the quotes).
If you will be reading or writing any Verilog variables inside the C++
functions, the Verilog signals must be declared with
:option:`/*verilator&32;public*/` metacomments.
@ -176,10 +184,9 @@ or "`ifdef`"'s may break other tools.
.. option:: /*verilator&32;no_clocker*/
Used after a signal declaration to indicate the signal is used as clock
or not. This information is used by Verilator to mark the signal as
clocker and propagate the clocker attribute automatically to derived
signals. See :vlopt:`--clk`.
Specifies that the signal is used as clock or not. This information is
used by Verilator to mark the signal and any derrived signals as
clocker. See :vlopt:`--clk`.
Same as :option:`clocker` and :option:`no_clocker` in configuration
files.
@ -482,6 +489,13 @@ or "`ifdef`"'s may break other tools.
Verilator) text that should be passed through to the XML output as a tag,
for use by downstream applications.
.. option:: /*verilator&32;trace_init_task*/
Attached to a DPI import to indicate that function should be called when
initializing tracing. This attribute is indented only to be used
internally in code that Verilator generates when :vlopt:`--lib-create`
or :vlopt:`--hierarchical` is used along with :vlopt:`--trace`.
.. option:: /*verilator&32;tracing_off*/
Disable waveform tracing for all future signals that are declared in

View File

@ -35,8 +35,10 @@ simulators.
Does Verilator run under Windows?
"""""""""""""""""""""""""""""""""
Yes, using Cygwin. Verilated output also compiles under Microsoft Visual
C++, but this is not tested every release.
Yes, ideally run Ubuntu under Windows Subsystem for Linux (WSL2).
Alternatively use Cygwin, though this tends to be slower and is not
regurally tested. Verilated output also compiles under Microsoft Visual
C++, but this is also not regurally tested.
Can you provide binaries?

View File

@ -78,10 +78,10 @@ OS Requirements
Verilator is developed and has primary testing on Ubuntu, with additional
testing on FreeBSD and Apple OS-X. Versions have also built on Redhat
Linux, HPUX and Solaris. It should run with minor porting on any
GNU/Linux-ish platform. Verilator also works on Windows under Cygwin, and
Windows under MinGW (gcc -mno-cygwin). Verilated output (not Verilator
itself) compiles under all the options above, plus using MSVC++.
Linux, and other flavors of GNU/Linux-ish platforms. Verilator also works
on Windows Subsystem for Linux (WSL2), Windows under Cygwin, and Windows
under MinGW (gcc -mno-cygwin). Verilated output (not Verilator itself)
compiles under all the options above, plus using MSVC++.
Install Prerequisites

View File

@ -70,10 +70,9 @@ Verilator is run in hierarchical mode on the whole SoC. Verilator will
make two models, one for the CPU hierarchy block, and one for the SoC. The
Verialted code for the SoC will automatically call the CPU Verilated model.
The current hierarchical Verilation is based on protect-lib. Each hierarchy
block is Verilated to a protect-lib. User modules of the hierarchy blocks
will see a tiny wrapper generated by protect-lib instead of the actual
design.
The current hierarchical Verilation is based on :vlopt:`--lib-create`. Each
hierarchy block is Verilated into a library. User modules of the hierarchy
blocks will see a tiny wrapper generated by :vlopt:`--lib-create`.
Usage

View File

@ -99,7 +99,7 @@ run:
@echo "-- DONE --------------------"
@echo "Note: Once this example is understood, see examples/cmake_tracing_sc."
@echo "Note: Also see the EXAMPLE section in the verilator manpage/document."
@echo "Note: See also https://verilator.org/guide/latest/examples.html"
clean mostlyclean distclean maintainer-clean:
@rm -rf build logs

View File

@ -40,7 +40,7 @@ default:
obj_dir/Vtop
@echo "-- DONE --------------------"
@echo "Note: Once this example is understood, see examples/make_tracing_c."
@echo "Note: Also see the EXAMPLE section in the verilator manpage/document."
@echo "Note: See also https://verilator.org/guide/latest/examples.html"
######################################################################

View File

@ -4,7 +4,8 @@
// any use, without warranty, 2017 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
// See also the EXAMPLE section in the verilator manpage/document.
// See also https://verilator.org/guide/latest/examples.html"
module top;
initial begin
$display("Hello World!");

View File

@ -49,7 +49,7 @@ run:
obj_dir/Vtop
@echo "-- DONE --------------------"
@echo "Note: Once this example is understood, see examples/make_tracing_sc."
@echo "Note: Also see the EXAMPLE section in the verilator manpage/document."
@echo "Note: See also https://verilator.org/guide/latest/examples.html"
######################################################################

View File

@ -4,7 +4,8 @@
// any use, without warranty, 2017 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
// See also the EXAMPLE section in the verilator manpage/document.
// See also https://verilator.org/guide/latest/examples.html"
module top;
initial begin
$display("Hello World!");

View File

@ -4,7 +4,8 @@
// any use, without warranty, 2019 by Todd Strader.
// SPDX-License-Identifier: CC0-1.0
// See also the EXAMPLE section in the verilator manpage/document.
// See also https://verilator.org/guide/latest/examples.html"
module top (input clk);
integer cyc = 0;

View File

@ -25,7 +25,7 @@
//=========================================================================
// Internal note:
//
// verilated.o may exist both in protect-lib (incrementally linked .a/.so)
// verilated.o may exist both in --lib-create (incrementally linked .a/.so)
// and the main module. Both refer the same instance of static
// variables/VL_THREAD_LOCAL in verilated.o such as Verilated, or
// VerilatedImpData. This is important to share that state, but the
@ -208,7 +208,7 @@ void VL_FATAL_MT(const char* filename, int linenum, const char* hier, const char
std::string _vl_string_vprintf(const char* formatp, va_list ap) VL_MT_SAFE {
va_list aq;
va_copy(aq, ap);
size_t len = VL_VSNPRINTF(nullptr, 0, formatp, aq);
const size_t len = VL_VSNPRINTF(nullptr, 0, formatp, aq);
va_end(aq);
if (VL_UNLIKELY(len < 1)) return "";
@ -308,27 +308,22 @@ vluint64_t vl_rand64() VL_MT_SAFE {
return result;
}
#ifndef VL_NO_LEGACY
// VL_RANDOM_W currently unused as $random always 32 bits, left for backwards compatibility
// LCOV_EXCL_START
WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE {
for (int i = 0; i < VL_WORDS_I(obits) - 1; ++i) outwp[i] = vl_rand64();
outwp[VL_WORDS_I(obits) - 1] = vl_rand64() & VL_MASK_E(obits);
for (int i = 0; i < VL_WORDS_I(obits); ++i) outwp[i] = vl_rand64();
// Last word is unclean
return outwp;
}
// LCOV_EXCL_STOP
#endif
IData VL_RANDOM_SEEDED_II(int obits, IData seed) VL_MT_SAFE {
IData VL_RANDOM_SEEDED_II(IData seed) VL_MT_SAFE {
Verilated::threadContextp()->randSeed(static_cast<int>(seed));
return VL_RANDOM_I(obits);
return VL_RANDOM_I();
}
IData VL_RAND_RESET_I(int obits) VL_MT_SAFE {
if (Verilated::threadContextp()->randReset() == 0) return 0;
IData data = ~0;
if (Verilated::threadContextp()->randReset() != 1) { // if 2, randomize
data = VL_RANDOM_I(obits);
data = VL_RANDOM_I();
}
data &= VL_MASK_I(obits);
return data;
@ -337,7 +332,7 @@ QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE {
if (Verilated::threadContextp()->randReset() == 0) return 0;
QData data = ~0ULL;
if (Verilated::threadContextp()->randReset() != 1) { // if 2, randomize
data = VL_RANDOM_Q(obits);
data = VL_RANDOM_Q();
}
data &= VL_MASK_Q(obits);
return data;
@ -387,7 +382,7 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, const WDataInP lwp, const WData
if (vw == 1) { // Single divisor word breaks rest of algorithm
vluint64_t k = 0;
for (int j = uw - 1; j >= 0; --j) {
vluint64_t unw64 = ((k << 32ULL) + static_cast<vluint64_t>(lwp[j]));
const vluint64_t unw64 = ((k << 32ULL) + static_cast<vluint64_t>(lwp[j]));
owp[j] = unw64 / static_cast<vluint64_t>(rwp[0]);
k = unw64 - static_cast<vluint64_t>(owp[j]) * static_cast<vluint64_t>(rwp[0]);
}
@ -444,7 +439,7 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, const WDataInP lwp, const WData
vlsint64_t t = 0; // Must be signed
vluint64_t k = 0;
for (int i = 0; i < vw; ++i) {
vluint64_t p = qhat * vn[i]; // Multiply by estimate
const vluint64_t p = qhat * vn[i]; // Multiply by estimate
t = un[i + j] - k - (p & 0xFFFFFFFFULL); // Subtract
un[i + j] = t;
k = (p >> 32ULL) - (t >> 32ULL);
@ -698,8 +693,8 @@ std::string _vl_vsformat_time(char* tmp, T ld, int timeunit, bool left, size_t w
}
}
} else {
double shiftd = vl_time_multiplier(shift);
double scaled = ld * shiftd;
const double shiftd = vl_time_multiplier(shift);
const double scaled = ld * shiftd;
const double fracDiv = vl_time_multiplier(fracDigits);
const double whole = scaled / fracDiv;
if (!fracDigits) {
@ -749,7 +744,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
}
} else { // Format character
inPct = false;
char fmt = pos[0];
const char fmt = pos[0];
switch (fmt) {
case '0': // FALLTHRU
case '1': // FALLTHRU
@ -809,7 +804,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
output += _vl_vsformat_time(t_tmp, d, timeunit, left, width);
} else {
const size_t len = pos - pctp + 1;
std::string fmts{pctp, len};
const std::string fmts{pctp, len};
VL_SNPRINTF(t_tmp, VL_VALUE_STRING_MAX_WIDTH, fmts.c_str(), d);
output += t_tmp;
}
@ -869,7 +864,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
}
digits = append.length();
}
int needmore = width - digits;
const int needmore = width - digits;
std::string padding;
if (needmore > 0) {
if (pctp && pctp[0] && pctp[1] == '0') { // %0
@ -892,7 +887,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
append = VL_DECIMAL_NW(lbits, lwp);
digits = append.length();
}
int needmore = width - digits;
const int needmore = width - digits;
std::string padding;
if (needmore > 0) {
if (pctp && pctp[0] && pctp[1] == '0') { // %0
@ -953,7 +948,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
case 'x':
for (; lsb >= 0; --lsb) {
lsb = (lsb / 4) * 4; // Next digit
IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xf;
const IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xf;
output += "0123456789abcdef"[charval];
}
break;
@ -1027,7 +1022,7 @@ static inline void _vl_vsss_read_str(FILE* fp, int& floc, const WDataInP fromp,
}
static inline char* _vl_vsss_read_bin(FILE* fp, int& floc, const WDataInP fromp,
const std::string& fstr, char* beginp, std::size_t n,
bool inhibit = false) {
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.
@ -1041,9 +1036,7 @@ static inline char* _vl_vsss_read_bin(FILE* fp, int& floc, const WDataInP fromp,
}
static inline 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(0, lsb, owp, ld & 1);
}
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 {
@ -1100,16 +1093,16 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
_vl_vsss_skipspace(fp, floc, fromp, fstr);
} else if (!inPct) { // Expected Format
_vl_vsss_skipspace(fp, floc, fromp, fstr);
int c = _vl_vsss_peek(fp, floc, fromp, fstr);
const int c = _vl_vsss_peek(fp, floc, fromp, fstr);
if (c != pos[0]) goto done;
_vl_vsss_advance(fp, floc);
} else { // Format character
// Skip loading spaces
inPct = false;
char fmt = pos[0];
const char fmt = pos[0];
switch (fmt) {
case '%': {
int c = _vl_vsss_peek(fp, floc, fromp, fstr);
const int c = _vl_vsss_peek(fp, floc, fromp, fstr);
if (c != '%') goto done;
_vl_vsss_advance(fp, floc);
break;
@ -1139,7 +1132,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
for (int i = 0; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
switch (fmt) {
case 'c': {
int c = _vl_vsss_peek(fp, floc, fromp, fstr);
const int c = _vl_vsss_peek(fp, floc, fromp, fstr);
if (c == EOF) goto done;
_vl_vsss_advance(fp, floc);
owp[0] = c;
@ -1292,7 +1285,7 @@ void _vl_vint_to_string(int obits, char* destoutp, const WDataInP sourcep) VL_MT
char* destp = destoutp;
for (; lsb >= 0; --lsb) {
lsb = (lsb / 8) * 8; // Next digit
IData charval = VL_BITRSHIFT_W(sourcep, lsb) & 0xff;
const IData charval = VL_BITRSHIFT_W(sourcep, lsb) & 0xff;
if (!start || charval) {
*destp++ = (charval == 0) ? ' ' : charval;
start = false; // Drop leading 0s
@ -1530,16 +1523,16 @@ IData VL_FREAD_I(int width, int array_lsb, int array_size, void* memp, IData fpi
// Prep for reading
IData read_count = 0;
IData read_elements = 0;
int start_shift = (width - 1) & ~7; // bit+7:bit gets first character
const int start_shift = (width - 1) & ~7; // bit+7:bit gets first character
int shift = start_shift;
// Read the data
// We process a character at a time, as then we don't need to deal
// with changing buffer sizes dynamically, etc.
while (true) {
int c = std::fgetc(fp);
const int c = std::fgetc(fp);
if (VL_UNLIKELY(c == EOF)) break;
// Shift value in
IData entry = read_elements + start - array_lsb;
const IData entry = read_elements + start - array_lsb;
if (width <= 8) {
CData* const datap = &(reinterpret_cast<CData*>(memp))[entry];
if (shift == start_shift) *datap = 0;
@ -1600,6 +1593,7 @@ IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_M
inPct = true;
} else if (!inPct) { // Normal text
prefix += *posp;
} else if (inPct && posp[0] == '0') { // %0
} else { // Format character
switch (std::tolower(*posp)) {
case '%':
@ -1727,14 +1721,14 @@ std::string VL_TOUPPER_NN(const std::string& ld) VL_MT_SAFE {
std::string VL_CVT_PACK_STR_NW(int lwords, const WDataInP lwp) VL_MT_SAFE {
// See also _vl_vint_to_string
char destout[VL_VALUE_STRING_MAX_CHARS + 1];
int obits = lwords * VL_EDATASIZE;
const int obits = lwords * VL_EDATASIZE;
int lsb = obits - 1;
bool start = true;
char* destp = destout;
size_t len = 0;
for (; lsb >= 0; --lsb) {
lsb = (lsb / 8) * 8; // Next digit
IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xff;
const IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xff;
if (!start || charval) {
*destp++ = (charval == 0) ? ' ' : charval;
++len;
@ -2068,7 +2062,7 @@ void VL_READMEM_N(bool hex, // Hex format, else binary
VL_FATAL_MT(filename.c_str(), rmem.linenum(), "",
"$readmem file address beyond bounds of array");
} else {
QData entry = addr - array_lsb;
const QData entry = addr - array_lsb;
if (bits <= 8) {
CData* const datap = &(reinterpret_cast<CData*>(memp))[entry];
rmem.setData(datap, value);
@ -2103,7 +2097,7 @@ void VL_WRITEMEM_N(bool hex, // Hex format, else binary
QData start, // First array row address to write
QData end // Last address to write, or ~0 when not specified
) VL_MT_SAFE {
QData addr_max = array_lsb + depth - 1;
const QData addr_max = array_lsb + depth - 1;
if (start < static_cast<QData>(array_lsb)) start = array_lsb;
if (end > addr_max) end = addr_max;
@ -2827,7 +2821,7 @@ size_t VerilatedVarProps::totalSize() const {
void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const {
if (VL_UNLIKELY(dim <= 0 || dim > udims())) return nullptr;
if (VL_UNLIKELY(indx < low(dim) || indx > high(dim))) return nullptr;
int indxAdj = indx - low(dim);
const int indxAdj = indx - low(dim);
vluint8_t* bytep = reinterpret_cast<vluint8_t*>(datap);
// If on index 1 of a 2 index array, then each index 1 is index2sz*entsz
size_t slicesz = entSize();
@ -2872,7 +2866,7 @@ void VerilatedScope::configure(VerilatedSyms* symsp, const char* prefixp, const
void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE {
// Slowpath - called once/scope*export at construction
// Insert a exported function into scope table
int funcnum = VerilatedImp::exportInsert(namep);
const int funcnum = VerilatedImp::exportInsert(namep);
if (!finalize) {
// Need two passes so we know array size to create
// Alternative is to dynamically stretch the array, which is more code, and slower.
@ -2914,7 +2908,7 @@ void VerilatedScope::varInsert(int finalize, const char* namep, void* datap, boo
} else {
// We could have a linked list of ranges, but really this whole thing needs
// to be generalized to support structs and unions, etc.
std::string msg
const std::string msg
= std::string{"Unsupported multi-dimensional public varInsert: "} + namep;
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
}
@ -2961,7 +2955,7 @@ void VerilatedScope::scopeDump() const {
VerilatedImp::exportName(i));
}
}
if (VerilatedVarNameMap* const varsp = this->varsp()) {
if (const VerilatedVarNameMap* const varsp = this->varsp()) {
for (const auto& i : *varsp) VL_PRINTF_MT(" VAR %p: %s\n", &(i.second), i.first);
}
}

View File

@ -359,7 +359,7 @@ protected:
} m_args VL_GUARDED_BY(m_argMutex);
// Implementation details
std::unique_ptr<VerilatedContextImpData> m_impdatap;
const std::unique_ptr<VerilatedContextImpData> m_impdatap;
// Coverage access
std::unique_ptr<VerilatedVirtualBase> m_coveragep; // Pointer for coveragep()

View File

@ -206,9 +206,9 @@ private:
}
// Forward to . so we have a whole word
std::string suffix = *bpost ? std::string{bpost + 1} : "";
const std::string suffix = *bpost ? std::string{bpost + 1} : "";
std::string out = prefix + "*" + suffix;
const std::string out = prefix + "*" + suffix;
// cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add
// <<"\ncho="<<out<<endl;
@ -219,7 +219,7 @@ private:
for (int i = 0; i < VerilatedCovConst::MAX_KEYS; ++i) {
if (itemp->m_keys[i] != VerilatedCovConst::KEY_UNDEF) {
// We don't compare keys, only values
std::string val = m_indexValues[itemp->m_vals[i]];
const std::string val = m_indexValues[itemp->m_vals[i]];
if (std::string::npos != val.find(match)) { // Found
return true;
}
@ -302,7 +302,7 @@ public:
// First two key/vals are filename
ckeyps[0] = "filename";
valps[0] = m_insertFilenamep;
std::string linestr = vlCovCvtToStr(m_insertLineno);
const std::string linestr = vlCovCvtToStr(m_insertLineno);
ckeyps[1] = "lineno";
valps[1] = linestr.c_str();
// Default page if not specified
@ -342,7 +342,7 @@ public:
m_insertp->m_vals[addKeynum] = valueIndex(val);
++addKeynum;
if (VL_UNCOVERABLE(!legalKey(key))) {
std::string msg
const std::string msg
= ("%Error: Coverage keys of one character, or letter+digit are illegal: "
+ key); // LCOV_EXCL_LINE
VL_FATAL_MT("", 0, "", msg.c_str());
@ -380,8 +380,9 @@ public:
for (int i = 0; i < VerilatedCovConst::MAX_KEYS; ++i) {
if (itemp->m_keys[i] != VerilatedCovConst::KEY_UNDEF) {
std::string key = VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]);
std::string val = m_indexValues[itemp->m_vals[i]];
const std::string key
= VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]);
const std::string val = m_indexValues[itemp->m_vals[i]];
if (key == VL_CIK_PER_INSTANCE) {
if (val != "0") per_instance = true;
}

View File

@ -68,7 +68,7 @@ svLogic svGetBitselLogic(const svLogicVecVal* sp, int bit) {
| (((sp[VL_BITWORD_I(bit)].bval >> VL_BITBIT_I(bit)) & 1) << 1));
}
void svPutBitselBit(svBitVecVal* dp, int bit, svBit s) { VL_ASSIGNBIT_WI(32, bit, dp, s); }
void svPutBitselBit(svBitVecVal* dp, int bit, svBit s) { VL_ASSIGNBIT_WI(bit, dp, s); }
void svPutBitselLogic(svLogicVecVal* dp, int bit, svLogic s) {
// Verilator doesn't support X/Z so only aval
dp[VL_BITWORD_I(bit)].aval = ((dp[VL_BITWORD_I(bit)].aval & ~(VL_UL(1) << VL_BITBIT_I(bit)))
@ -428,13 +428,13 @@ void* svGetArrElemPtr(const svOpenArrayHandle h, int indx1, ...) {
switch (varp->udims()) {
case 1: datap = _vl_svGetArrElemPtr(h, 1, indx1, 0, 0); break;
case 2: {
int indx2 = va_arg(ap, int);
const int indx2 = va_arg(ap, int);
datap = _vl_svGetArrElemPtr(h, 2, indx1, indx2, 0);
break;
}
case 3: {
int indx2 = va_arg(ap, int);
int indx3 = va_arg(ap, int);
const int indx2 = va_arg(ap, int);
const int indx3 = va_arg(ap, int);
datap = _vl_svGetArrElemPtr(h, 3, indx1, indx2, indx3);
break;
}

View File

@ -73,14 +73,13 @@ extern void VL_PRINTF_MT(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE;
/// Print a debug message from internals with standard prefix, with printf style format
extern void VL_DBG_MSGF(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE;
inline IData VL_RANDOM_I(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_I(obits); }
inline QData VL_RANDOM_Q(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_Q(obits); }
#ifndef VL_NO_LEGACY
// EMIT_RULE: VL_RANDOM: oclean=dirty
inline IData VL_RANDOM_I() VL_MT_SAFE { return vl_rand64(); }
inline QData VL_RANDOM_Q() VL_MT_SAFE { return vl_rand64(); }
extern WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp);
#endif
extern IData VL_RANDOM_SEEDED_II(int obits, IData seed) VL_MT_SAFE;
extern IData VL_RANDOM_SEEDED_II(IData seed) VL_MT_SAFE;
inline IData VL_URANDOM_RANGE_I(IData hi, IData lo) {
vluint64_t rnd = vl_rand64();
const vluint64_t rnd = vl_rand64();
if (VL_LIKELY(hi > lo)) {
// (hi - lo + 1) can be zero when hi is UINT_MAX and lo is zero
if (VL_UNLIKELY(hi - lo + 1 == 0)) return rnd;
@ -363,13 +362,13 @@ vluint64_t vl_time_pow10(int n) VL_PURE;
#define VL_CLEAN_QQ(obits, lbits, lhs) ((lhs)&VL_MASK_Q(obits))
// EMIT_RULE: VL_ASSIGNCLEAN: oclean=clean; obits==lbits;
#define VL_ASSIGNCLEAN_W(obits, owp, lwp) VL_CLEAN_WW((obits), (obits), (owp), (lwp))
#define VL_ASSIGNCLEAN_W(obits, owp, lwp) VL_CLEAN_WW((obits), (owp), (lwp))
static inline WDataOutP _vl_clean_inplace_w(int obits, WDataOutP owp) VL_MT_SAFE {
const int words = VL_WORDS_I(obits);
owp[words - 1] &= VL_MASK_E(obits);
return owp;
}
static inline WDataOutP VL_CLEAN_WW(int obits, int, WDataOutP owp, WDataInP const lwp) VL_MT_SAFE {
static inline WDataOutP VL_CLEAN_WW(int obits, WDataOutP owp, WDataInP const lwp) VL_MT_SAFE {
const int words = VL_WORDS_I(obits);
for (int i = 0; (i < (words - 1)); ++i) owp[i] = lwp[i];
owp[words - 1] = lwp[words - 1] & VL_MASK_E(obits);
@ -397,37 +396,37 @@ static inline WDataOutP VL_ASSIGN_W(int obits, WDataOutP owp, WDataInP const lwp
}
// EMIT_RULE: VL_ASSIGNBIT: rclean=clean;
static inline void VL_ASSIGNBIT_II(int, int bit, CData& lhsr, IData rhs) VL_PURE {
static inline void VL_ASSIGNBIT_II(int bit, CData& lhsr, IData rhs) VL_PURE {
lhsr = ((lhsr & ~(VL_UL(1) << VL_BITBIT_I(bit))) | (rhs << VL_BITBIT_I(bit)));
}
static inline void VL_ASSIGNBIT_II(int, int bit, SData& lhsr, IData rhs) VL_PURE {
static inline void VL_ASSIGNBIT_II(int bit, SData& lhsr, IData rhs) VL_PURE {
lhsr = ((lhsr & ~(VL_UL(1) << VL_BITBIT_I(bit))) | (rhs << VL_BITBIT_I(bit)));
}
static inline void VL_ASSIGNBIT_II(int, int bit, IData& lhsr, IData rhs) VL_PURE {
static inline void VL_ASSIGNBIT_II(int bit, IData& lhsr, IData rhs) VL_PURE {
lhsr = ((lhsr & ~(VL_UL(1) << VL_BITBIT_I(bit))) | (rhs << VL_BITBIT_I(bit)));
}
static inline void VL_ASSIGNBIT_QI(int, int bit, QData& lhsr, QData rhs) VL_PURE {
static inline void VL_ASSIGNBIT_QI(int bit, QData& lhsr, QData rhs) VL_PURE {
lhsr = ((lhsr & ~(1ULL << VL_BITBIT_Q(bit))) | (static_cast<QData>(rhs) << VL_BITBIT_Q(bit)));
}
static inline void VL_ASSIGNBIT_WI(int, int bit, WDataOutP owp, IData rhs) VL_MT_SAFE {
EData orig = owp[VL_BITWORD_E(bit)];
static inline void VL_ASSIGNBIT_WI(int bit, WDataOutP owp, IData rhs) VL_MT_SAFE {
const EData orig = owp[VL_BITWORD_E(bit)];
owp[VL_BITWORD_E(bit)] = ((orig & ~(VL_EUL(1) << VL_BITBIT_E(bit)))
| (static_cast<EData>(rhs) << VL_BITBIT_E(bit)));
}
// Alternative form that is an instruction faster when rhs is constant one.
static inline void VL_ASSIGNBIT_IO(int, int bit, CData& lhsr, IData) VL_PURE {
static inline void VL_ASSIGNBIT_IO(int bit, CData& lhsr) VL_PURE {
lhsr = (lhsr | (VL_UL(1) << VL_BITBIT_I(bit)));
}
static inline void VL_ASSIGNBIT_IO(int, int bit, SData& lhsr, IData) VL_PURE {
static inline void VL_ASSIGNBIT_IO(int bit, SData& lhsr) VL_PURE {
lhsr = (lhsr | (VL_UL(1) << VL_BITBIT_I(bit)));
}
static inline void VL_ASSIGNBIT_IO(int, int bit, IData& lhsr, IData) VL_PURE {
static inline void VL_ASSIGNBIT_IO(int bit, IData& lhsr) VL_PURE {
lhsr = (lhsr | (VL_UL(1) << VL_BITBIT_I(bit)));
}
static inline void VL_ASSIGNBIT_QO(int, int bit, QData& lhsr, IData) VL_PURE {
static inline void VL_ASSIGNBIT_QO(int bit, QData& lhsr) VL_PURE {
lhsr = (lhsr | (1ULL << VL_BITBIT_Q(bit)));
}
static inline void VL_ASSIGNBIT_WO(int, int bit, WDataOutP owp, IData) VL_MT_SAFE {
static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE {
const EData orig = owp[VL_BITWORD_E(bit)];
owp[VL_BITWORD_E(bit)] = (orig | (VL_EUL(1) << VL_BITBIT_E(bit)));
}
@ -588,9 +587,9 @@ static inline WDataOutP VL_EXTENDS_WW(int obits, int lbits, WDataOutP owp,
// REDUCTION OPERATORS
// EMIT_RULE: VL_REDAND: oclean=clean; lclean==clean; obits=1;
#define VL_REDAND_II(obits, lbits, lhs) ((lhs) == VL_MASK_I(lbits))
#define VL_REDAND_IQ(obits, lbits, lhs) ((lhs) == VL_MASK_Q(lbits))
static inline IData VL_REDAND_IW(int, int lbits, WDataInP const lwp) VL_MT_SAFE {
#define VL_REDAND_II(lbits, lhs) ((lhs) == VL_MASK_I(lbits))
#define VL_REDAND_IQ(lbits, lhs) ((lhs) == VL_MASK_Q(lbits))
static inline IData VL_REDAND_IW(int lbits, WDataInP const lwp) VL_MT_SAFE {
const int words = VL_WORDS_I(lbits);
EData combine = lwp[0];
for (int i = 1; i < words - 1; ++i) combine &= lwp[i];
@ -696,11 +695,11 @@ static inline IData VL_COUNTONES_W(int words, WDataInP const lwp) VL_MT_SAFE {
// EMIT_RULE: VL_COUNTBITS_II: oclean = false; lhs clean
static inline IData VL_COUNTBITS_I(int lbits, IData lhs, IData ctrl0, IData ctrl1,
IData ctrl2) VL_PURE {
int ctrlSum = (ctrl0 & 0x1) + (ctrl1 & 0x1) + (ctrl2 & 0x1);
const int ctrlSum = (ctrl0 & 0x1) + (ctrl1 & 0x1) + (ctrl2 & 0x1);
if (ctrlSum == 3) {
return VL_COUNTONES_I(lhs);
} else if (ctrlSum == 0) {
IData mask = (lbits == 32) ? -1 : ((1 << lbits) - 1);
const IData mask = (lbits == 32) ? -1 : ((1 << lbits) - 1);
return VL_COUNTONES_I(~lhs & mask);
} else {
return (lbits == 32) ? 32 : lbits;
@ -771,7 +770,7 @@ static inline IData VL_CLOG2_Q(QData lhs) VL_PURE {
return shifts;
}
static inline IData VL_CLOG2_W(int words, WDataInP const lwp) VL_MT_SAFE {
EData adjust = (VL_COUNTONES_W(words, lwp) == 1) ? 0 : 1;
const EData adjust = (VL_COUNTONES_W(words, lwp) == 1) ? 0 : 1;
for (int i = words - 1; i >= 0; --i) {
if (VL_UNLIKELY(lwp[i])) { // Shorter worst case if predict not taken
for (int bit = VL_EDATASIZE - 1; bit >= 0; --bit) {
@ -862,52 +861,52 @@ static inline int _vl_cmp_w(int words, WDataInP const lwp, WDataInP const rwp) V
return 0; // ==
}
#define VL_LTS_IWW(obits, lbits, rbbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) < 0)
#define VL_LTES_IWW(obits, lbits, rbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) <= 0)
#define VL_GTS_IWW(obits, lbits, rbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) > 0)
#define VL_GTES_IWW(obits, lbits, rbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) >= 0)
#define VL_LTS_IWW(lbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) < 0)
#define VL_LTES_IWW(lbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) <= 0)
#define VL_GTS_IWW(lbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) > 0)
#define VL_GTES_IWW(lbits, lwp, rwp) (_vl_cmps_w(lbits, lwp, rwp) >= 0)
static inline IData VL_GTS_III(int, int lbits, int, IData lhs, IData rhs) VL_PURE {
static inline IData VL_GTS_III(int lbits, IData lhs, IData rhs) VL_PURE {
// For lbits==32, this becomes just a single instruction, otherwise ~5.
// GCC 3.3.4 sign extension bugs on AMD64 architecture force us to use quad logic
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs); // Q for gcc
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs); // Q for gcc
return lhs_signed > rhs_signed;
}
static inline IData VL_GTS_IQQ(int, int lbits, int, QData lhs, QData rhs) VL_PURE {
static inline IData VL_GTS_IQQ(int lbits, QData lhs, QData rhs) VL_PURE {
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs);
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs);
return lhs_signed > rhs_signed;
}
static inline IData VL_GTES_III(int, int lbits, int, IData lhs, IData rhs) VL_PURE {
static inline IData VL_GTES_III(int lbits, IData lhs, IData rhs) VL_PURE {
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs); // Q for gcc
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs); // Q for gcc
return lhs_signed >= rhs_signed;
}
static inline IData VL_GTES_IQQ(int, int lbits, int, QData lhs, QData rhs) VL_PURE {
static inline IData VL_GTES_IQQ(int lbits, QData lhs, QData rhs) VL_PURE {
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs);
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs);
return lhs_signed >= rhs_signed;
}
static inline IData VL_LTS_III(int, int lbits, int, IData lhs, IData rhs) VL_PURE {
static inline IData VL_LTS_III(int lbits, IData lhs, IData rhs) VL_PURE {
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs); // Q for gcc
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs); // Q for gcc
return lhs_signed < rhs_signed;
}
static inline IData VL_LTS_IQQ(int, int lbits, int, QData lhs, QData rhs) VL_PURE {
static inline IData VL_LTS_IQQ(int lbits, QData lhs, QData rhs) VL_PURE {
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs);
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs);
return lhs_signed < rhs_signed;
}
static inline IData VL_LTES_III(int, int lbits, int, IData lhs, IData rhs) VL_PURE {
static inline IData VL_LTES_III(int lbits, IData lhs, IData rhs) VL_PURE {
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs); // Q for gcc
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs); // Q for gcc
return lhs_signed <= rhs_signed;
}
static inline IData VL_LTES_IQQ(int, int lbits, int, QData lhs, QData rhs) VL_PURE {
static inline IData VL_LTES_IQQ(int lbits, QData lhs, QData rhs) VL_PURE {
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs);
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs);
return lhs_signed <= rhs_signed;
@ -943,7 +942,7 @@ static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp, WDataInP const lwp
static inline void VL_NEGATE_INPLACE_W(int words, WDataOutP owp_lwp) VL_MT_SAFE {
EData carry = 1;
for (int i = 0; i < words; ++i) {
EData word = ~owp_lwp[i] + carry;
const EData word = ~owp_lwp[i] + carry;
carry = (word < ~owp_lwp[i]);
owp_lwp[i] = word;
}
@ -1002,18 +1001,18 @@ static inline WDataOutP VL_MUL_W(int words, WDataOutP owp, WDataInP const lwp,
return owp;
}
static inline IData VL_MULS_III(int, int lbits, int, IData lhs, IData rhs) VL_PURE {
static inline IData VL_MULS_III(int lbits, IData lhs, IData rhs) VL_PURE {
const vlsint32_t lhs_signed = VL_EXTENDS_II(32, lbits, lhs);
const vlsint32_t rhs_signed = VL_EXTENDS_II(32, lbits, rhs);
return lhs_signed * rhs_signed;
}
static inline QData VL_MULS_QQQ(int, int lbits, int, QData lhs, QData rhs) VL_PURE {
static inline QData VL_MULS_QQQ(int lbits, QData lhs, QData rhs) VL_PURE {
const vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs);
const vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs);
return lhs_signed * rhs_signed;
}
static inline WDataOutP VL_MULS_WWW(int, int lbits, int, WDataOutP owp, WDataInP const lwp,
static inline WDataOutP VL_MULS_WWW(int lbits, WDataOutP owp, WDataInP const lwp,
WDataInP const rwp) VL_MT_SAFE {
const int words = VL_WORDS_I(lbits);
// cppcheck-suppress variableScope
@ -1022,13 +1021,13 @@ static inline WDataOutP VL_MULS_WWW(int, int lbits, int, WDataOutP owp, WDataInP
WData rwstore[VL_MULS_MAX_WORDS];
WDataInP lwusp = lwp;
WDataInP rwusp = rwp;
EData lneg = VL_SIGN_E(lbits, lwp[words - 1]);
const EData lneg = VL_SIGN_E(lbits, lwp[words - 1]);
if (lneg) { // Negate lhs
lwusp = lwstore;
VL_NEGATE_W(words, lwstore, lwp);
lwstore[words - 1] &= VL_MASK_E(lbits); // Clean it
}
EData rneg = VL_SIGN_E(lbits, rwp[words - 1]);
const EData rneg = VL_SIGN_E(lbits, rwp[words - 1]);
if (rneg) { // Negate rhs
rwusp = rwstore;
VL_NEGATE_W(words, rwstore, rwp);
@ -1221,31 +1220,27 @@ QData VL_POWSS_QQW(int obits, int, int rbits, QData lhs, WDataInP const rwp, boo
// INTERNAL: Stuff LHS bit 0++ into OUTPUT at specified offset
// ld may be "dirty", output is clean
static inline void _vl_insert_II(int, CData& lhsr, IData ld, int hbit, int lbit,
int rbits) VL_PURE {
static inline void _vl_insert_II(CData& lhsr, IData ld, int hbit, int lbit, int rbits) VL_PURE {
const IData cleanmask = VL_MASK_I(rbits);
const IData insmask = (VL_MASK_I(hbit - lbit + 1)) << lbit;
lhsr = (lhsr & ~insmask) | ((ld << lbit) & (insmask & cleanmask));
}
static inline void _vl_insert_II(int, SData& lhsr, IData ld, int hbit, int lbit,
int rbits) VL_PURE {
static inline void _vl_insert_II(SData& lhsr, IData ld, int hbit, int lbit, int rbits) VL_PURE {
const IData cleanmask = VL_MASK_I(rbits);
const IData insmask = (VL_MASK_I(hbit - lbit + 1)) << lbit;
lhsr = (lhsr & ~insmask) | ((ld << lbit) & (insmask & cleanmask));
}
static inline void _vl_insert_II(int, IData& lhsr, IData ld, int hbit, int lbit,
int rbits) VL_PURE {
static inline void _vl_insert_II(IData& lhsr, IData ld, int hbit, int lbit, int rbits) VL_PURE {
const IData cleanmask = VL_MASK_I(rbits);
const IData insmask = (VL_MASK_I(hbit - lbit + 1)) << lbit;
lhsr = (lhsr & ~insmask) | ((ld << lbit) & (insmask & cleanmask));
}
static inline void _vl_insert_QQ(int, QData& lhsr, QData ld, int hbit, int lbit,
int rbits) VL_PURE {
static inline void _vl_insert_QQ(QData& lhsr, QData ld, int hbit, int lbit, int rbits) VL_PURE {
const QData cleanmask = VL_MASK_Q(rbits);
const QData insmask = (VL_MASK_Q(hbit - lbit + 1)) << lbit;
lhsr = (lhsr & ~insmask) | ((ld << lbit) & (insmask & cleanmask));
}
static inline void _vl_insert_WI(int, WDataOutP owp, IData ld, int hbit, int lbit,
static inline void _vl_insert_WI(WDataOutP owp, IData ld, int hbit, int lbit,
int rbits = 0) VL_MT_SAFE {
const int hoffset = VL_BITBIT_E(hbit);
const int loffset = VL_BITBIT_E(lbit);
@ -1278,7 +1273,7 @@ static inline void _vl_insert_WI(int, WDataOutP owp, IData ld, int hbit, int lbi
// INTERNAL: Stuff large LHS bit 0++ into OUTPUT at specified offset
// lwp may be "dirty"
static inline void _vl_insert_WW(int, WDataOutP owp, WDataInP const lwp, int hbit, int lbit,
static inline void _vl_insert_WW(WDataOutP owp, WDataInP const lwp, int hbit, int lbit,
int rbits = 0) VL_MT_SAFE {
const int hoffset = VL_BITBIT_E(hbit);
const int loffset = VL_BITBIT_E(lbit);
@ -1334,19 +1329,19 @@ static inline void _vl_insert_WW(int, WDataOutP owp, WDataInP const lwp, int hbi
}
}
static inline void _vl_insert_WQ(int obits, WDataOutP owp, QData ld, int hbit, int lbit,
static inline void _vl_insert_WQ(WDataOutP owp, QData ld, int hbit, int lbit,
int rbits = 0) VL_MT_SAFE {
VlWide<VL_WQ_WORDS_E> lwp;
VL_SET_WQ(lwp, ld);
_vl_insert_WW(obits, owp, lwp, hbit, lbit, rbits);
_vl_insert_WW(owp, lwp, hbit, lbit, rbits);
}
// EMIT_RULE: VL_REPLICATE: oclean=clean>width32, dirty<=width32; lclean=clean; rclean==clean;
// RHS MUST BE CLEAN CONSTANT.
#define VL_REPLICATE_IOI(obits, lbits, rbits, ld, rep) (-(ld)) // Iff lbits==1
#define VL_REPLICATE_QOI(obits, lbits, rbits, ld, rep) (-(static_cast<QData>(ld))) // Iff lbits==1
#define VL_REPLICATE_IOI(lbits, ld, rep) (-(ld)) // Iff lbits==1
#define VL_REPLICATE_QOI(lbits, ld, rep) (-(static_cast<QData>(ld))) // Iff lbits==1
static inline IData VL_REPLICATE_III(int, int lbits, int, IData ld, IData rep) VL_PURE {
static inline IData VL_REPLICATE_III(int lbits, IData ld, IData rep) VL_PURE {
IData returndata = ld;
for (unsigned i = 1; i < rep; ++i) {
returndata = returndata << lbits;
@ -1354,7 +1349,7 @@ static inline IData VL_REPLICATE_III(int, int lbits, int, IData ld, IData rep) V
}
return returndata;
}
static inline QData VL_REPLICATE_QII(int, int lbits, int, IData ld, IData rep) VL_PURE {
static inline QData VL_REPLICATE_QII(int lbits, IData ld, IData rep) VL_PURE {
QData returndata = ld;
for (unsigned i = 1; i < rep; ++i) {
returndata = returndata << lbits;
@ -1362,27 +1357,27 @@ static inline QData VL_REPLICATE_QII(int, int lbits, int, IData ld, IData rep) V
}
return returndata;
}
static inline WDataOutP VL_REPLICATE_WII(int obits, int lbits, int, WDataOutP owp, IData ld,
static inline WDataOutP VL_REPLICATE_WII(int lbits, WDataOutP owp, IData ld,
IData rep) VL_MT_SAFE {
owp[0] = ld;
for (unsigned i = 1; i < rep; ++i) {
_vl_insert_WI(obits, owp, ld, i * lbits + lbits - 1, i * lbits);
_vl_insert_WI(owp, ld, i * lbits + lbits - 1, i * lbits);
}
return owp;
}
static inline WDataOutP VL_REPLICATE_WQI(int obits, int lbits, int, WDataOutP owp, QData ld,
static inline WDataOutP VL_REPLICATE_WQI(int lbits, WDataOutP owp, QData ld,
IData rep) VL_MT_SAFE {
VL_SET_WQ(owp, ld);
for (unsigned i = 1; i < rep; ++i) {
_vl_insert_WQ(obits, owp, ld, i * lbits + lbits - 1, i * lbits);
_vl_insert_WQ(owp, ld, i * lbits + lbits - 1, i * lbits);
}
return owp;
}
static inline WDataOutP VL_REPLICATE_WWI(int obits, int lbits, int, WDataOutP owp,
WDataInP const lwp, IData rep) VL_MT_SAFE {
static inline WDataOutP VL_REPLICATE_WWI(int lbits, WDataOutP owp, WDataInP const lwp,
IData rep) VL_MT_SAFE {
for (int i = 0; i < VL_WORDS_I(lbits); ++i) owp[i] = lwp[i];
for (unsigned i = 1; i < rep; ++i) {
_vl_insert_WW(obits, owp, lwp, i * lbits + lbits - 1, i * lbits);
_vl_insert_WW(owp, lwp, i * lbits + lbits - 1, i * lbits);
}
return owp;
}
@ -1391,7 +1386,7 @@ static inline WDataOutP VL_REPLICATE_WWI(int obits, int lbits, int, WDataOutP ow
// Special "fast" versions for slice sizes that are a power of 2. These use
// shifts and masks to execute faster than the slower for-loop approach where a
// subset of bits is copied in during each iteration.
static inline IData VL_STREAML_FAST_III(int, int lbits, int, IData ld, IData rd_log2) VL_PURE {
static inline IData VL_STREAML_FAST_III(int lbits, IData ld, IData rd_log2) VL_PURE {
// Pre-shift bits in most-significant slice:
//
// If lbits is not a multiple of the slice size (i.e., lbits % rd != 0),
@ -1429,7 +1424,7 @@ static inline IData VL_STREAML_FAST_III(int, int lbits, int, IData ld, IData rd_
return ret >> (VL_IDATASIZE - lbits);
}
static inline QData VL_STREAML_FAST_QQI(int, int lbits, int, QData ld, IData rd_log2) VL_PURE {
static inline QData VL_STREAML_FAST_QQI(int lbits, QData ld, IData rd_log2) VL_PURE {
// Pre-shift bits in most-significant slice (see comment in VL_STREAML_FAST_III)
QData ret = ld;
if (rd_log2) {
@ -1461,7 +1456,7 @@ static inline QData VL_STREAML_FAST_QQI(int, int lbits, int, QData ld, IData rd_
}
// Regular "slow" streaming operators
static inline IData VL_STREAML_III(int, int lbits, int, IData ld, IData rd) VL_PURE {
static inline IData VL_STREAML_III(int lbits, IData ld, IData rd) VL_PURE {
IData ret = 0;
// Slice size should never exceed the lhs width
const IData mask = VL_MASK_I(rd);
@ -1473,7 +1468,7 @@ static inline IData VL_STREAML_III(int, int lbits, int, IData ld, IData rd) VL_P
return ret;
}
static inline QData VL_STREAML_QQI(int, int lbits, int, QData ld, IData rd) VL_PURE {
static inline QData VL_STREAML_QQI(int lbits, QData ld, IData rd) VL_PURE {
QData ret = 0;
// Slice size should never exceed the lhs width
const QData mask = VL_MASK_Q(rd);
@ -1485,7 +1480,7 @@ static inline QData VL_STREAML_QQI(int, int lbits, int, QData ld, IData rd) VL_P
return ret;
}
static inline WDataOutP VL_STREAML_WWI(int, int lbits, int, WDataOutP owp, WDataInP const lwp,
static inline WDataOutP VL_STREAML_WWI(int lbits, WDataOutP owp, WDataInP const lwp,
IData rd) VL_MT_SAFE {
VL_ZERO_W(lbits, owp);
// Slice size should never exceed the lhs width
@ -1496,7 +1491,8 @@ static inline WDataOutP VL_STREAML_WWI(int, int lbits, int, WDataOutP owp, WData
for (int sbit = 0; sbit < ssize && sbit < lbits - istart; ++sbit) {
// Extract a single bit from lwp and shift it to the correct
// location for owp.
EData bit = (VL_BITRSHIFT_W(lwp, (istart + sbit)) & 1) << VL_BITBIT_E(ostart + sbit);
const EData bit = (VL_BITRSHIFT_W(lwp, (istart + sbit)) & 1)
<< VL_BITBIT_E(ostart + sbit);
owp[VL_BITWORD_E(ostart + sbit)] |= bit;
}
}
@ -1522,63 +1518,63 @@ static inline WDataOutP VL_CONCAT_WII(int obits, int lbits, int rbits, WDataOutP
IData rd) VL_MT_SAFE {
owp[0] = rd;
for (int i = 1; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_vl_insert_WI(obits, owp, ld, rbits + lbits - 1, rbits);
_vl_insert_WI(owp, ld, rbits + lbits - 1, rbits);
return owp;
}
static inline WDataOutP VL_CONCAT_WWI(int obits, int lbits, int rbits, WDataOutP owp,
WDataInP const lwp, IData rd) VL_MT_SAFE {
owp[0] = rd;
for (int i = 1; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_vl_insert_WW(obits, owp, lwp, rbits + lbits - 1, rbits);
_vl_insert_WW(owp, lwp, rbits + lbits - 1, rbits);
return owp;
}
static inline WDataOutP VL_CONCAT_WIW(int obits, int lbits, int rbits, WDataOutP owp, IData ld,
WDataInP const rwp) VL_MT_SAFE {
for (int i = 0; i < VL_WORDS_I(rbits); ++i) owp[i] = rwp[i];
for (int i = VL_WORDS_I(rbits); i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_vl_insert_WI(obits, owp, ld, rbits + lbits - 1, rbits);
_vl_insert_WI(owp, ld, rbits + lbits - 1, rbits);
return owp;
}
static inline WDataOutP VL_CONCAT_WIQ(int obits, int lbits, int rbits, WDataOutP owp, IData ld,
QData rd) VL_MT_SAFE {
VL_SET_WQ(owp, rd);
for (int i = VL_WQ_WORDS_E; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_vl_insert_WI(obits, owp, ld, rbits + lbits - 1, rbits);
_vl_insert_WI(owp, ld, rbits + lbits - 1, rbits);
return owp;
}
static inline WDataOutP VL_CONCAT_WQI(int obits, int lbits, int rbits, WDataOutP owp, QData ld,
IData rd) VL_MT_SAFE {
owp[0] = rd;
for (int i = 1; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_vl_insert_WQ(obits, owp, ld, rbits + lbits - 1, rbits);
_vl_insert_WQ(owp, ld, rbits + lbits - 1, rbits);
return owp;
}
static inline WDataOutP VL_CONCAT_WQQ(int obits, int lbits, int rbits, WDataOutP owp, QData ld,
QData rd) VL_MT_SAFE {
VL_SET_WQ(owp, rd);
for (int i = VL_WQ_WORDS_E; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_vl_insert_WQ(obits, owp, ld, rbits + lbits - 1, rbits);
_vl_insert_WQ(owp, ld, rbits + lbits - 1, rbits);
return owp;
}
static inline WDataOutP VL_CONCAT_WWQ(int obits, int lbits, int rbits, WDataOutP owp,
WDataInP const lwp, QData rd) VL_MT_SAFE {
VL_SET_WQ(owp, rd);
for (int i = VL_WQ_WORDS_E; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_vl_insert_WW(obits, owp, lwp, rbits + lbits - 1, rbits);
_vl_insert_WW(owp, lwp, rbits + lbits - 1, rbits);
return owp;
}
static inline WDataOutP VL_CONCAT_WQW(int obits, int lbits, int rbits, WDataOutP owp, QData ld,
WDataInP const rwp) VL_MT_SAFE {
for (int i = 0; i < VL_WORDS_I(rbits); ++i) owp[i] = rwp[i];
for (int i = VL_WORDS_I(rbits); i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_vl_insert_WQ(obits, owp, ld, rbits + lbits - 1, rbits);
_vl_insert_WQ(owp, ld, rbits + lbits - 1, rbits);
return owp;
}
static inline WDataOutP VL_CONCAT_WWW(int obits, int lbits, int rbits, WDataOutP owp,
WDataInP const lwp, WDataInP const rwp) VL_MT_SAFE {
for (int i = 0; i < VL_WORDS_I(rbits); ++i) owp[i] = rwp[i];
for (int i = VL_WORDS_I(rbits); i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_vl_insert_WW(obits, owp, lwp, rbits + lbits - 1, rbits);
_vl_insert_WW(owp, lwp, rbits + lbits - 1, rbits);
return owp;
}
@ -1613,7 +1609,7 @@ static inline WDataOutP VL_SHIFTL_WWI(int obits, int, int, WDataOutP owp, WDataI
for (int i = word_shift; i < VL_WORDS_I(obits); ++i) owp[i] = lwp[i - word_shift];
} else {
for (int i = 0; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
_vl_insert_WW(obits, owp, lwp, obits - 1, rd);
_vl_insert_WW(owp, lwp, obits - 1, rd);
}
return owp;
}
@ -1766,7 +1762,8 @@ static inline WDataOutP VL_SHIFTRS_WWI(int obits, int lbits, int, WDataOutP owp,
owp[lmsw] &= VL_MASK_E(lbits);
} else {
const int loffset = rd & VL_SIZEBITS_E;
int nbitsonright = VL_EDATASIZE - loffset; // bits that end up in lword (know loffset!=0)
const int nbitsonright
= VL_EDATASIZE - loffset; // bits that end up in lword (know loffset!=0)
// Middle words
const int words = VL_WORDS_I(obits - rd);
for (int i = 0; i < words; ++i) {
@ -1835,14 +1832,13 @@ static inline QData VL_SHIFTRS_QQQ(int obits, int lbits, int rbits, QData lhs, Q
// Bit selection
// EMIT_RULE: VL_BITSEL: oclean=dirty; rclean==clean;
#define VL_BITSEL_IIII(obits, lbits, rbits, zbits, lhs, rhs) ((lhs) >> (rhs))
#define VL_BITSEL_QIII(obits, lbits, rbits, zbits, lhs, rhs) ((lhs) >> (rhs))
#define VL_BITSEL_QQII(obits, lbits, rbits, zbits, lhs, rhs) ((lhs) >> (rhs))
#define VL_BITSEL_IQII(obits, lbits, rbits, zbits, lhs, rhs) (static_cast<IData>((lhs) >> (rhs)))
#define VL_BITSEL_IIII(lbits, lhs, rhs) ((lhs) >> (rhs))
#define VL_BITSEL_QIII(lbits, lhs, rhs) ((lhs) >> (rhs))
#define VL_BITSEL_QQII(lbits, lhs, rhs) ((lhs) >> (rhs))
#define VL_BITSEL_IQII(lbits, lhs, rhs) (static_cast<IData>((lhs) >> (rhs)))
static inline IData VL_BITSEL_IWII(int, int lbits, int, int, WDataInP const lwp,
IData rd) VL_MT_SAFE {
int word = VL_BITWORD_E(rd);
static inline IData VL_BITSEL_IWII(int lbits, WDataInP const lwp, IData rd) VL_MT_SAFE {
const int word = VL_BITWORD_E(rd);
if (VL_UNLIKELY(rd > static_cast<IData>(lbits))) {
return ~0; // Spec says you can go outside the range of a array. Don't coredump if so.
// We return all 1's as that's more likely to find bugs (?) than 0's.
@ -1853,27 +1849,24 @@ static inline IData VL_BITSEL_IWII(int, int lbits, int, int, WDataInP const lwp,
// EMIT_RULE: VL_RANGE: oclean=lclean; out=dirty
// <msb> & <lsb> MUST BE CLEAN (currently constant)
#define VL_SEL_IIII(obits, lbits, rbits, tbits, lhs, lsb, width) ((lhs) >> (lsb))
#define VL_SEL_QQII(obits, lbits, rbits, tbits, lhs, lsb, width) ((lhs) >> (lsb))
#define VL_SEL_IQII(obits, lbits, rbits, tbits, lhs, lsb, width) \
(static_cast<IData>((lhs) >> (lsb)))
#define VL_SEL_IIII(lbits, lhs, lsb, width) ((lhs) >> (lsb))
#define VL_SEL_QQII(lbits, lhs, lsb, width) ((lhs) >> (lsb))
#define VL_SEL_IQII(lbits, lhs, lsb, width) (static_cast<IData>((lhs) >> (lsb)))
static inline IData VL_SEL_IWII(int, int lbits, int, int, WDataInP const lwp, IData lsb,
IData width) VL_MT_SAFE {
int msb = lsb + width - 1;
static inline IData VL_SEL_IWII(int lbits, WDataInP const lwp, IData lsb, IData width) VL_MT_SAFE {
const int msb = lsb + width - 1;
if (VL_UNLIKELY(msb >= lbits)) {
return ~0; // Spec says you can go outside the range of a array. Don't coredump if so.
} else if (VL_BITWORD_E(msb) == VL_BITWORD_E(static_cast<int>(lsb))) {
return VL_BITRSHIFT_W(lwp, lsb);
} else {
// 32 bit extraction may span two words
int nbitsfromlow = VL_EDATASIZE - VL_BITBIT_E(lsb); // bits that come from low word
const int nbitsfromlow = VL_EDATASIZE - VL_BITBIT_E(lsb); // bits that come from low word
return ((lwp[VL_BITWORD_E(msb)] << nbitsfromlow) | VL_BITRSHIFT_W(lwp, lsb));
}
}
static inline QData VL_SEL_QWII(int, int lbits, int, int, WDataInP const lwp, IData lsb,
IData width) VL_MT_SAFE {
static inline QData VL_SEL_QWII(int lbits, WDataInP const lwp, IData lsb, IData width) VL_MT_SAFE {
const int msb = lsb + width - 1;
if (VL_UNLIKELY(msb > lbits)) {
return ~0; // Spec says you can go outside the range of a array. Don't coredump if so.
@ -1886,7 +1879,7 @@ static inline QData VL_SEL_QWII(int, int lbits, int, int, WDataInP const lwp, ID
return (hi << nbitsfromlow) | lo;
} else {
// 64 bit extraction may span three words
int nbitsfromlow = VL_EDATASIZE - VL_BITBIT_E(lsb);
const int nbitsfromlow = VL_EDATASIZE - VL_BITBIT_E(lsb);
const QData hi = (lwp[VL_BITWORD_E(msb)]);
const QData mid = (lwp[VL_BITWORD_E(lsb) + 1]);
const QData lo = VL_BITRSHIFT_W(lwp, lsb);
@ -1894,8 +1887,8 @@ static inline QData VL_SEL_QWII(int, int lbits, int, int, WDataInP const lwp, ID
}
}
static inline WDataOutP VL_SEL_WWII(int obits, int lbits, int, int, WDataOutP owp,
WDataInP const lwp, IData lsb, IData width) VL_MT_SAFE {
static inline WDataOutP VL_SEL_WWII(int obits, int lbits, WDataOutP owp, WDataInP const lwp,
IData lsb, IData width) VL_MT_SAFE {
const int msb = lsb + width - 1;
const int word_shift = VL_BITWORD_E(lsb);
if (VL_UNLIKELY(msb > lbits)) { // Outside bounds,
@ -1927,7 +1920,7 @@ static inline WDataOutP VL_SEL_WWII(int obits, int lbits, int, int, WDataOutP ow
// Return QData from double (numeric)
// EMIT_RULE: VL_RTOIROUND_Q_D: oclean=dirty; lclean==clean/real
static inline QData VL_RTOIROUND_Q_D(int, double lhs) VL_PURE {
static inline QData VL_RTOIROUND_Q_D(double lhs) VL_PURE {
// IEEE format: [63]=sign [62:52]=exp+1023 [51:0]=mantissa
// This does not need to support subnormals as they are sub-integral
lhs = VL_ROUND(lhs);
@ -1944,8 +1937,8 @@ static inline QData VL_RTOIROUND_Q_D(int, double lhs) VL_PURE {
if (lhs < 0) out = -out;
return out;
}
static inline IData VL_RTOIROUND_I_D(int bits, double lhs) VL_PURE {
return static_cast<IData>(VL_RTOIROUND_Q_D(bits, lhs));
static inline IData VL_RTOIROUND_I_D(double lhs) VL_PURE {
return static_cast<IData>(VL_RTOIROUND_Q_D(lhs));
}
static inline WDataOutP VL_RTOIROUND_W_D(int obits, WDataOutP owp, double lhs) VL_PURE {
// IEEE format: [63]=sign [62:52]=exp+1023 [51:0]=mantissa
@ -1959,7 +1952,7 @@ static inline WDataOutP VL_RTOIROUND_W_D(int obits, WDataOutP owp, double lhs) V
if (lsb < 0) {
VL_SET_WQ(owp, mantissa >> -lsb);
} else if (lsb < obits) {
_vl_insert_WQ(obits, owp, mantissa, lsb + 52, lsb);
_vl_insert_WQ(owp, mantissa, lsb + 52, lsb);
}
if (lhs < 0) VL_NEGATE_INPLACE_W(VL_WORDS_I(obits), owp);
return owp;
@ -1971,48 +1964,48 @@ static inline WDataOutP VL_RTOIROUND_W_D(int obits, WDataOutP owp, double lhs) V
// EMIT_RULE: VL_ASSIGNRANGE: rclean=dirty;
static inline void VL_ASSIGNSEL_IIII(int rbits, int obits, int lsb, CData& lhsr,
IData rhs) VL_PURE {
_vl_insert_II(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
_vl_insert_II(lhsr, rhs, lsb + obits - 1, lsb, rbits);
}
static inline void VL_ASSIGNSEL_IIII(int rbits, int obits, int lsb, SData& lhsr,
IData rhs) VL_PURE {
_vl_insert_II(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
_vl_insert_II(lhsr, rhs, lsb + obits - 1, lsb, rbits);
}
static inline void VL_ASSIGNSEL_IIII(int rbits, int obits, int lsb, IData& lhsr,
IData rhs) VL_PURE {
_vl_insert_II(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
_vl_insert_II(lhsr, rhs, lsb + obits - 1, lsb, rbits);
}
static inline void VL_ASSIGNSEL_QIII(int rbits, int obits, int lsb, QData& lhsr,
IData rhs) VL_PURE {
_vl_insert_QQ(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
_vl_insert_QQ(lhsr, rhs, lsb + obits - 1, lsb, rbits);
}
static inline void VL_ASSIGNSEL_QQII(int rbits, int obits, int lsb, QData& lhsr,
QData rhs) VL_PURE {
_vl_insert_QQ(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
_vl_insert_QQ(lhsr, rhs, lsb + obits - 1, lsb, rbits);
}
static inline void VL_ASSIGNSEL_QIIQ(int rbits, int obits, int lsb, QData& lhsr,
QData rhs) VL_PURE {
_vl_insert_QQ(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
_vl_insert_QQ(lhsr, rhs, lsb + obits - 1, lsb, rbits);
}
// static inline void VL_ASSIGNSEL_IIIW(int obits, int lsb, IData& lhsr, WDataInP const rwp)
// VL_MT_SAFE { Illegal, as lhs width >= rhs width
static inline void VL_ASSIGNSEL_WIII(int rbits, int obits, int lsb, WDataOutP owp,
IData rhs) VL_MT_SAFE {
_vl_insert_WI(obits, owp, rhs, lsb + obits - 1, lsb, rbits);
_vl_insert_WI(owp, rhs, lsb + obits - 1, lsb, rbits);
}
static inline void VL_ASSIGNSEL_WIIQ(int rbits, int obits, int lsb, WDataOutP owp,
QData rhs) VL_MT_SAFE {
_vl_insert_WQ(obits, owp, rhs, lsb + obits - 1, lsb, rbits);
_vl_insert_WQ(owp, rhs, lsb + obits - 1, lsb, rbits);
}
static inline void VL_ASSIGNSEL_WIIW(int rbits, int obits, int lsb, WDataOutP owp,
WDataInP const rwp) VL_MT_SAFE {
_vl_insert_WW(obits, owp, rwp, lsb + obits - 1, lsb, rbits);
_vl_insert_WW(owp, rwp, lsb + obits - 1, lsb, rbits);
}
//======================================================================
// Triops
static inline WDataOutP VL_COND_WIWW(int obits, int, int, int, WDataOutP owp, int cond,
WDataInP const w1p, WDataInP const w2p) VL_MT_SAFE {
static inline WDataOutP VL_COND_WIWW(int obits, WDataOutP owp, int cond, WDataInP const w1p,
WDataInP const w2p) VL_MT_SAFE {
const int words = VL_WORDS_I(obits);
for (int i = 0; i < words; ++i) owp[i] = cond ? w1p[i] : w2p[i];
return owp;
@ -2187,15 +2180,14 @@ inline std::string VL_CVT_PACK_STR_NI(IData lhs) VL_PURE {
inline std::string VL_CONCATN_NNN(const std::string& lhs, const std::string& rhs) VL_PURE {
return lhs + rhs;
}
inline std::string VL_REPLICATEN_NNQ(int, int, int, const std::string& lhs, IData rep) VL_PURE {
inline std::string VL_REPLICATEN_NNQ(const std::string& lhs, IData rep) VL_PURE {
std::string out;
out.reserve(lhs.length() * rep);
for (unsigned times = 0; times < rep; ++times) out += lhs;
return out;
}
inline std::string VL_REPLICATEN_NNI(int obits, int lbits, int rbits, const std::string& lhs,
IData rep) VL_PURE {
return VL_REPLICATEN_NNQ(obits, lbits, rbits, lhs, rep);
inline std::string VL_REPLICATEN_NNI(const std::string& lhs, IData rep) VL_PURE {
return VL_REPLICATEN_NNQ(lhs, rep);
}
inline IData VL_LEN_IN(const std::string& ld) { return ld.length(); }
@ -2220,31 +2212,31 @@ extern void VL_TIMEFORMAT_IINI(int units, int precision, const std::string& suff
extern IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_MT_SAFE;
inline IData VL_VALUEPLUSARGS_INI(int rbits, const std::string& ld, CData& rdr) VL_MT_SAFE {
VlWide<2> rwp;
IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
const IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
if (got) rdr = rwp[0];
return got;
}
inline IData VL_VALUEPLUSARGS_INI(int rbits, const std::string& ld, SData& rdr) VL_MT_SAFE {
VlWide<2> rwp;
IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
const IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
if (got) rdr = rwp[0];
return got;
}
inline IData VL_VALUEPLUSARGS_INI(int rbits, const std::string& ld, IData& rdr) VL_MT_SAFE {
VlWide<2> rwp;
IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
const IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
if (got) rdr = rwp[0];
return got;
}
inline IData VL_VALUEPLUSARGS_INQ(int rbits, const std::string& ld, QData& rdr) VL_MT_SAFE {
VlWide<2> rwp;
IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
const IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
if (got) rdr = VL_SET_QW(rwp);
return got;
}
inline IData VL_VALUEPLUSARGS_INQ(int rbits, const std::string& ld, double& rdr) VL_MT_SAFE {
VlWide<2> rwp;
IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
const IData got = VL_VALUEPLUSARGS_INW(rbits, ld, rwp);
if (got) rdr = VL_CVT_D_Q(VL_SET_QW(rwp));
return got;
}

View File

@ -277,7 +277,7 @@ public: // But only for verilated*.cpp
IData fdNewMcd(const char* filenamep) VL_MT_SAFE_EXCLUDES(m_fdMutex) {
const VerilatedLockGuard lock{m_fdMutex};
if (m_fdFreeMct.empty()) return 0;
IData idx = m_fdFreeMct.back();
const IData idx = m_fdFreeMct.back();
m_fdFreeMct.pop_back();
m_fdps[idx] = std::fopen(filenamep, "w");
if (VL_UNLIKELY(!m_fdps[idx])) return 0;
@ -299,7 +299,7 @@ public: // But only for verilated*.cpp
m_fdFree[i] = id;
}
}
IData idx = m_fdFree.back();
const IData idx = m_fdFree.back();
m_fdFree.pop_back();
m_fdps[idx] = fp;
return (idx | (1UL << 31)); // bit 31 indicates not MCD
@ -334,7 +334,7 @@ public: // But only for verilated*.cpp
const VerilatedLockGuard lock{m_fdMutex};
if (VL_BITISSET_I(fdi, 31)) {
// Non-MCD case
IData idx = VL_MASK_I(31) & fdi;
const IData idx = VL_MASK_I(31) & fdi;
if (VL_UNLIKELY(idx >= m_fdps.size())) return;
if (VL_UNLIKELY(idx <= 2)) return; // stdout/stdin/stderr
if (VL_UNLIKELY(!m_fdps[idx])) return; // Already free

View File

@ -27,8 +27,8 @@
// Profile record, private class used only by this header
class VerilatedProfilerRec final {
std::string m_name; // Hashed name of mtask/etc
size_t m_counterNumber = 0; // Which counter has data
const std::string m_name; // Hashed name of mtask/etc
const size_t m_counterNumber = 0; // Which counter has data
public:
// METHODS
VerilatedProfilerRec(size_t counterNumber, const std::string& name)

View File

@ -192,7 +192,7 @@ void VerilatedRestore::close() VL_MT_UNSAFE_ONE {
void VerilatedSave::flush() VL_MT_UNSAFE_ONE {
m_assertOne.check();
if (VL_UNLIKELY(!isOpen())) return;
vluint8_t* wp = m_bufp;
const vluint8_t* wp = m_bufp;
while (true) {
const ssize_t remaining = (m_cp - wp);
if (remaining == 0) break;

View File

@ -279,7 +279,7 @@ inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, float& rhs) {
return os.read(&rhs, sizeof(rhs));
}
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, const std::string& rhs) {
vluint32_t len = rhs.length();
const vluint32_t len = rhs.length();
os << len;
return os.write(rhs.data(), len);
}

View File

@ -192,8 +192,8 @@ public:
class VerilatedDpiOpenVar final {
// MEMBERS
const VerilatedVarProps* m_propsp; // Variable properties
void* m_datap; // Location of data (local to thread always, so safe)
const VerilatedVarProps* const m_propsp; // Variable properties
void* const m_datap; // Location of data (local to thread always, so safe)
public:
// CONSTRUCTORS
VerilatedDpiOpenVar(const VerilatedVarProps* propsp, void* datap)
@ -230,10 +230,10 @@ public:
class VerilatedVar final : public VerilatedVarProps {
// MEMBERS
void* m_datap; // Location of data
const char* m_namep; // Name - slowpath
void* const m_datap; // Location of data
const char* const m_namep; // Name - slowpath
protected:
bool m_isParam;
const bool m_isParam;
friend class VerilatedScope;
// CONSTRUCTORS
VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype,

View File

@ -217,12 +217,12 @@ private:
// Store the size atomically, so we can spin wait
std::atomic<size_t> m_ready_size;
VlThreadPool* m_poolp; // Our associated thread pool
VlThreadPool* const m_poolp; // Our associated thread pool
bool m_profiling; // Is profiling enabled?
const bool m_profiling; // Is profiling enabled?
std::atomic<bool> m_exiting; // Worker thread should exit
std::thread m_cthread; // Underlying C++ thread record
VerilatedContext* m_contextp; // Context for spawned thread
VerilatedContext* const m_contextp; // Context for spawned thread
VL_UNCOPYABLE(VlWorkerThread);
@ -274,7 +274,7 @@ class VlThreadPool final {
// MEMBERS
std::vector<VlWorkerThread*> m_workers; // our workers
bool m_profiling; // is profiling enabled?
const bool m_profiling; // is profiling enabled?
// Support profiling -- we can append records of profiling events
// to this vector with very low overhead, and then dump them out

View File

@ -267,7 +267,7 @@ template <> void VerilatedTrace<VL_DERIVED_T>::flushBase() {
// Callbacks to run on global events
template <> void VerilatedTrace<VL_DERIVED_T>::onFlush(void* selfp) {
// This calls 'flush' on the derived classo (which must then get any mutex)
// This calls 'flush' on the derived class (which must then get any mutex)
reinterpret_cast<VL_DERIVED_T*>(selfp)->flush();
}

View File

@ -79,10 +79,10 @@ public:
// Readmem/Writemem operation classes
class VlReadMem final {
bool m_hex; // Hex format
int m_bits; // Bit width of values
const bool m_hex; // Hex format
const int m_bits; // Bit width of values
const std::string& m_filename; // Filename
QData m_end; // End address (as specified by user)
const QData m_end; // End address (as specified by user)
FILE* m_fp; // File handle for filename
QData m_addr; // Next address to read
int m_linenum; // Line number last read from file
@ -96,8 +96,8 @@ public:
};
class VlWriteMem final {
bool m_hex; // Hex format
int m_bits; // Bit width of values
const bool m_hex; // Hex format
const int m_bits; // Bit width of values
FILE* m_fp; // File handle for filename
QData m_addr; // Next address to write
public:

View File

@ -281,7 +281,7 @@ void VerilatedVcd::bufferResize(vluint64_t minsize) {
// minsize is size of largest write. We buffer at least 8 times as much data,
// writing when we are 3/4 full (with thus 2*minsize remaining free)
if (VL_UNLIKELY(minsize > m_wrChunkSize)) {
char* oldbufp = m_wrBufp;
const char* oldbufp = m_wrBufp;
m_wrChunkSize = minsize * 2;
m_wrBufp = new char[m_wrChunkSize * 8];
std::memcpy(m_wrBufp, oldbufp, m_writep - oldbufp);
@ -298,7 +298,7 @@ void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE {
// When it gets nearly full we dump it using this routine which calls write()
// This is much faster than using buffered I/O
if (VL_UNLIKELY(!isOpen())) return;
char* wp = m_wrBufp;
const char* wp = m_wrBufp;
while (true) {
const ssize_t remaining = (m_writep - wp);
if (remaining == 0) break;
@ -311,7 +311,7 @@ void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE {
if (VL_UNCOVERABLE(errno != EAGAIN && errno != EINTR)) {
// LCOV_EXCL_START
// write failed, presume error (perhaps out of disk space)
std::string msg
const std::string msg
= std::string{"VerilatedVcd::bufferFlush: "} + std::strerror(errno);
VL_FATAL_MT("", 0, "", msg.c_str());
closeErr();
@ -386,7 +386,7 @@ void VerilatedVcd::dumpHeader() {
const std::string& decl = i.second;
// Determine difference between the old and new names
const char* hiername = hiernamestr.c_str();
const char* const hiername = hiernamestr.c_str();
const char* lp = lastName;
const char* np = hiername;
lastName = hiername;

View File

@ -74,7 +74,7 @@ private:
int m_modDepth = 0; // Depth of module hierarchy
char* m_wrBufp; // Output buffer
char* m_wrFlushp; // Output buffer flush trigger location
const char* m_wrFlushp; // Output buffer flush trigger location
char* m_writep; // Write pointer into output buffer
vluint64_t m_wrChunkSize; // Output buffer size
vluint64_t m_wroteBytes = 0; // Number of bytes written to this file

View File

@ -123,8 +123,8 @@ public:
class VerilatedVpioTimedCb final : public VerilatedVpio {
// A handle to a timed callback created with vpi_register_cb
// User can call vpi_remove_cb or vpi_release_handle on it
vluint64_t m_id; // Unique id/sequence number to find schedule's event
QData m_time;
const vluint64_t m_id; // Unique id/sequence number to find schedule's event
const QData m_time;
public:
VerilatedVpioTimedCb(vluint64_t id, QData time)
@ -141,8 +141,8 @@ public:
class VerilatedVpioReasonCb final : public VerilatedVpio {
// A handle to a non-timed callback created with vpi_register_cb
// User can call vpi_remove_cb or vpi_release_handle on it
vluint64_t m_id; // Unique id/sequence number to find schedule's event
PLI_INT32 m_reason; // VPI callback reason code
const vluint64_t m_id; // Unique id/sequence number to find schedule's event
const PLI_INT32 m_reason; // VPI callback reason code
public:
// cppcheck-suppress uninitVar // m_value
@ -158,7 +158,7 @@ public:
};
class VerilatedVpioConst final : public VerilatedVpio {
vlsint32_t m_num;
const vlsint32_t m_num;
public:
explicit VerilatedVpioConst(vlsint32_t num)
@ -219,7 +219,7 @@ public:
};
class VerilatedVpioRange final : public VerilatedVpio {
const VerilatedRange* m_range;
const VerilatedRange* const m_range;
public:
explicit VerilatedVpioRange(const VerilatedRange* range)
@ -235,7 +235,7 @@ public:
class VerilatedVpioRangeIter final : public VerilatedVpio {
// Only supports 1 dimension
const VerilatedRange* m_range;
const VerilatedRange* const m_range;
bool m_done = false;
public:
@ -258,7 +258,7 @@ public:
class VerilatedVpioScope VL_NOT_FINAL : public VerilatedVpio {
protected:
const VerilatedScope* m_scopep;
const VerilatedScope* const m_scopep;
public:
explicit VerilatedVpioScope(const VerilatedScope* scopep)
@ -352,7 +352,7 @@ public:
};
class VerilatedVpioVarIter final : public VerilatedVpio {
const VerilatedScope* m_scopep;
const VerilatedScope* const m_scopep;
VerilatedVarNameMap::const_iterator m_it;
bool m_started = false;
@ -389,9 +389,9 @@ public:
class VerilatedVpioMemoryWordIter final : public VerilatedVpio {
const vpiHandle m_handle;
const VerilatedVar* m_varp;
const VerilatedVar* const m_varp;
vlsint32_t m_iteration;
vlsint32_t m_direction;
const vlsint32_t m_direction;
bool m_done = false;
public:
@ -413,7 +413,7 @@ public:
delete this; // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle
return nullptr;
}
vpiHandle result = vpi_handle_by_index(m_handle, m_iteration);
const vpiHandle result = vpi_handle_by_index(m_handle, m_iteration);
iterationInc();
return result;
}
@ -457,7 +457,7 @@ public:
delete this; // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle
return nullptr;
}
const VerilatedScope* modp = *m_it++;
const VerilatedScope* const modp = *m_it++;
return (new VerilatedVpioModule{modp})->castVpiHandle();
}
};
@ -595,7 +595,7 @@ public:
const auto last = std::prev(cbObjList.end()); // prevent looping over newly added elements
for (auto it = cbObjList.begin(); true;) {
// cbReasonRemove sets to nullptr, so we know on removal the old end() will still exist
bool was_last = it == last;
const bool was_last = it == last;
if (VL_UNLIKELY(it->invalid())) { // Deleted earlier, cleanup
it = cbObjList.erase(it);
if (was_last) break;
@ -1111,7 +1111,7 @@ const char* VerilatedVpiError::strFromVpiProp(PLI_INT32 vpiVal) VL_MT_SAFE {
#define SELF_CHECK_RESULT_CSTR(got, exp) \
if (0 != std::strcmp((got), (exp))) { \
std::string msg \
const std::string msg \
= std::string{"%Error: "} + "GOT = '" + (got) + "'" + " EXP = '" + (exp) + "'"; \
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); \
}
@ -1305,7 +1305,7 @@ vpiHandle vpi_register_cb(p_cb_data cb_data_p) {
QData time = 0;
if (cb_data_p->time) time = VL_SET_QII(cb_data_p->time->high, cb_data_p->time->low);
const QData abstime = VL_TIME_Q() + time;
vluint64_t id = VerilatedVpiImp::nextCallbackId();
const vluint64_t id = VerilatedVpiImp::nextCallbackId();
VerilatedVpioTimedCb* const vop = new VerilatedVpioTimedCb{id, abstime};
VerilatedVpiImp::cbTimedAdd(id, cb_data_p, abstime);
return vop->castVpiHandle();
@ -1410,7 +1410,7 @@ vpiHandle vpi_handle_by_index(vpiHandle object, PLI_INT32 indx) {
VerilatedVpiImp::assertOneCheck();
VL_VPI_ERROR_RESET_();
// Memory words are not indexable
VerilatedVpioMemoryWord* const vop = VerilatedVpioMemoryWord::castp(object);
const VerilatedVpioMemoryWord* const vop = VerilatedVpioMemoryWord::castp(object);
if (VL_UNLIKELY(vop)) return nullptr;
const VerilatedVpioVar* const varop = VerilatedVpioVar::castp(object);
if (VL_LIKELY(varop)) {
@ -1442,10 +1442,10 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
VL_VPI_ERROR_RESET_();
switch (type) {
case vpiLeftRange: {
if (VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object)) {
if (const VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
return (new VerilatedVpioConst{vop->rangep()->left()})->castVpiHandle();
} else if (VerilatedVpioRange* const vop = VerilatedVpioRange::castp(object)) {
} else if (const VerilatedVpioRange* const vop = VerilatedVpioRange::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
return (new VerilatedVpioConst{vop->rangep()->left()})->castVpiHandle();
}
@ -1455,10 +1455,10 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
return nullptr;
}
case vpiRightRange: {
if (VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object)) {
if (const VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
return (new VerilatedVpioConst{vop->rangep()->right()})->castVpiHandle();
} else if (VerilatedVpioRange* const vop = VerilatedVpioRange::castp(object)) {
} else if (const VerilatedVpioRange* const vop = VerilatedVpioRange::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
return (new VerilatedVpioConst{vop->rangep()->right()})->castVpiHandle();
}
@ -1468,18 +1468,18 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
return nullptr;
}
case vpiIndex: {
VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) return nullptr;
const vlsint32_t val = vop->index();
return (new VerilatedVpioConst{val})->castVpiHandle();
}
case vpiScope: {
VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object);
const VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object);
if (VL_UNLIKELY(!vop)) return nullptr;
return (new VerilatedVpioScope{vop->scopep()})->castVpiHandle();
}
case vpiParent: {
VerilatedVpioMemoryWord* const vop = VerilatedVpioMemoryWord::castp(object);
const VerilatedVpioMemoryWord* const vop = VerilatedVpioMemoryWord::castp(object);
if (VL_UNLIKELY(!vop)) return nullptr;
return (new VerilatedVpioVar{vop->varp(), vop->scopep()})->castVpiHandle();
}
@ -1697,7 +1697,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
// Maximum required size is for binary string, one byte per bit plus null termination
static VL_THREAD_LOCAL char t_outStr[VL_VALUE_STRING_MAX_WORDS * VL_EDATASIZE + 1];
// cppcheck-suppress variableScope
static VL_THREAD_LOCAL int t_outStrSz = sizeof(t_outStr) - 1;
const static VL_THREAD_LOCAL int t_outStrSz = sizeof(t_outStr) - 1;
// We used to presume vpiValue.format = vpiIntVal or if single bit vpiScalarVal
// This may cause backward compatibility issues with older code.
if (valuep->format == vpiVectorVal) {
@ -1718,14 +1718,14 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
t_out[0].bval = 0;
return;
} else if (varp->vltype() == VLVT_UINT64) {
QData data = *(reinterpret_cast<QData*>(varDatap));
const QData data = *(reinterpret_cast<QData*>(varDatap));
t_out[1].aval = static_cast<IData>(data >> 32ULL);
t_out[1].bval = 0;
t_out[0].aval = static_cast<IData>(data);
t_out[0].bval = 0;
return;
} else if (varp->vltype() == VLVT_WDATA) {
int words = VL_WORDS_I(varp->packed().elements());
const int words = VL_WORDS_I(varp->packed().elements());
if (VL_UNCOVERABLE(words >= VL_VALUE_STRING_MAX_WORDS)) {
VL_FATAL_MT(__FILE__, __LINE__, "",
"vpi_get_value with more than VL_VALUE_STRING_MAX_WORDS; increase and "
@ -1741,7 +1741,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
} else if (valuep->format == vpiBinStrVal) {
valuep->value.str = t_outStr;
int bits = varp->packed().elements();
CData* datap = (reinterpret_cast<CData*>(varDatap));
const CData* datap = (reinterpret_cast<CData*>(varDatap));
int i;
if (bits > t_outStrSz) {
// limit maximum size of output to size of buffer to prevent overrun.
@ -1754,7 +1754,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
VL_VALUE_STRING_MAX_WORDS, bits);
}
for (i = 0; i < bits; ++i) {
char val = (datap[i >> 3] >> (i & 7)) & 1;
const char val = (datap[i >> 3] >> (i & 7)) & 1;
t_outStr[bits - i - 1] = val ? '1' : '0';
}
t_outStr[i] = '\0';
@ -1763,7 +1763,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
valuep->value.str = t_outStr;
int chars = (varp->packed().elements() + 2) / 3;
const int bytes = VL_BYTES_I(varp->packed().elements());
CData* datap = (reinterpret_cast<CData*>(varDatap));
const CData* datap = (reinterpret_cast<CData*>(varDatap));
int i;
if (chars > t_outStrSz) {
// limit maximum size of output to size of buffer to prevent overrun.
@ -1788,7 +1788,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
if (i == (chars - 1)) {
// most signifcant char, mask off non existant bits when vector
// size is not a multiple of 3
unsigned int rem = varp->packed().elements() % 3;
const unsigned int rem = varp->packed().elements() % 3;
if (rem) {
// generate bit mask & zero non existant bits
val &= (1 << rem) - 1;
@ -1821,7 +1821,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
} else if (valuep->format == vpiHexStrVal) {
valuep->value.str = t_outStr;
int chars = (varp->packed().elements() + 3) >> 2;
CData* datap = (reinterpret_cast<CData*>(varDatap));
const CData* datap = (reinterpret_cast<CData*>(varDatap));
int i;
if (chars > t_outStrSz) {
// limit maximum size of output to size of buffer to prevent overrun.
@ -1855,7 +1855,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
} else {
valuep->value.str = t_outStr;
int bytes = VL_BYTES_I(varp->packed().elements());
CData* datap = (reinterpret_cast<CData*>(varDatap));
const CData* datap = (reinterpret_cast<CData*>(varDatap));
int i;
if (bytes > t_outStrSz) {
// limit maximum size of output to size of buffer to prevent overrun.
@ -1899,13 +1899,13 @@ void vpi_get_value(vpiHandle object, p_vpi_value valuep) {
VL_VPI_ERROR_RESET_();
if (VL_UNLIKELY(!valuep)) return;
if (VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object)) {
if (const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object)) {
vl_get_value(vop->varp(), vop->varDatap(), valuep, vop->fullname());
return;
} else if (const VerilatedVpioParam* const vop = VerilatedVpioParam::castp(object)) {
vl_get_value(vop->varp(), vop->varDatap(), valuep, vop->fullname());
return;
} else if (VerilatedVpioConst* const vop = VerilatedVpioConst::castp(object)) {
} else if (const VerilatedVpioConst* const vop = VerilatedVpioConst::castp(object)) {
if (valuep->format == vpiIntVal) {
valuep->value.integer = vop->num();
return;
@ -1970,9 +1970,9 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
} else if (valuep->format == vpiBinStrVal) {
const int bits = vop->varp()->packed().elements();
const int len = std::strlen(valuep->value.str);
CData* datap = (reinterpret_cast<CData*>(vop->varDatap()));
CData* const datap = (reinterpret_cast<CData*>(vop->varDatap()));
for (int i = 0; i < bits; ++i) {
char set = (i < len) ? (valuep->value.str[len - i - 1] == '1') : 0;
const char set = (i < len) ? (valuep->value.str[len - i - 1] == '1') : 0;
// zero bits 7:1 of byte when assigning to bit 0, else
// or in 1 if bit set
if (i & 7) {
@ -1986,7 +1986,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
const int chars = (vop->varp()->packed().elements() + 2) / 3;
const int bytes = VL_BYTES_I(vop->varp()->packed().elements());
const int len = std::strlen(valuep->value.str);
CData* datap = (reinterpret_cast<CData*>(vop->varDatap()));
CData* const datap = (reinterpret_cast<CData*>(vop->varDatap()));
div_t idx;
datap[0] = 0; // reset zero'th byte
for (int i = 0; i < chars; ++i) {
@ -1997,7 +1997,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
idx = div(i * 3, 8);
if (i < len) {
// ignore illegal chars
char digit = valuep->value.str[len - i - 1];
const char digit = valuep->value.str[len - i - 1];
if (digit >= '0' && digit <= '7') {
val.half = digit - '0';
} else {
@ -2064,8 +2064,8 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
}
} else if (valuep->format == vpiHexStrVal) {
const int chars = (vop->varp()->packed().elements() + 3) >> 2;
CData* datap = (reinterpret_cast<CData*>(vop->varDatap()));
char* val = valuep->value.str;
CData* const datap = (reinterpret_cast<CData*>(vop->varDatap()));
const char* val = valuep->value.str;
// skip hex ident if one is detected at the start of the string
if (val[0] == '0' && (val[1] == 'x' || val[1] == 'X')) val += 2;
const int len = std::strlen(val);
@ -2073,7 +2073,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
char hex;
// compute hex digit value
if (i < len) {
char digit = val[len - i - 1];
const char digit = val[len - i - 1];
if (digit >= '0' && digit <= '9') {
hex = digit - '0';
} else if (digit >= 'a' && digit <= 'f') {
@ -2105,7 +2105,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
} else if (valuep->format == vpiStringVal) {
const int bytes = VL_BYTES_I(vop->varp()->packed().elements());
const int len = std::strlen(valuep->value.str);
CData* datap = (reinterpret_cast<CData*>(vop->varDatap()));
CData* const datap = (reinterpret_cast<CData*>(vop->varDatap()));
for (int i = 0; i < bytes; ++i) {
// prepend with 0 values before placing string the least significant bytes
datap[i] = (i < len) ? valuep->value.str[len - i - 1] : 0;
@ -2167,7 +2167,7 @@ void vpi_get_time(vpiHandle object, p_vpi_time time_p) {
return;
} else if (time_p->type == vpiScaledRealTime) {
double dtime = VL_TIME_D();
if (VerilatedVpioScope* const vop = VerilatedVpioScope::castp(object)) {
if (const VerilatedVpioScope* const vop = VerilatedVpioScope::castp(object)) {
const int scalePow10
= Verilated::threadContextp()->timeprecision() - vop->scopep()->timeunit();
const double scale = vl_time_multiplier(scalePow10); // e.g. 0.0001
@ -2287,7 +2287,7 @@ PLI_INT32 vpi_release_handle(vpiHandle object) {
PLI_INT32 vpi_get_vlog_info(p_vpi_vlog_info vlog_info_p) VL_MT_SAFE {
VerilatedVpiImp::assertOneCheck();
VL_VPI_ERROR_RESET_();
auto argc_argv = Verilated::threadContextp()->impp()->argc_argv();
const auto argc_argv = Verilated::threadContextp()->impp()->argc_argv();
vlog_info_p->argc = argc_argv.first;
vlog_info_p->argv = argc_argv.second;
vlog_info_p->product = const_cast<PLI_BYTE8*>(Verilated::productName());

View File

@ -333,7 +333,8 @@ typedef signed __int32 ssize_t; ///< signed size_t; returned from read()
# include <stdint.h> // Linux and most flavors
# include <sys/types.h> // __WORDSIZE
# include <unistd.h> // ssize_t
typedef char vlsint8_t; ///< 8-bit signed type
// Arm64 gcc 9.3.0 defaults to unsigned char, not signed char
typedef signed char vlsint8_t; ///< 8-bit signed type
typedef uint8_t vluint8_t; ///< 8-bit unsigned type
typedef short vlsint16_t; ///< 16-bit signed type
typedef uint16_t vluint16_t; ///< 16-bit unsigned type

View File

@ -23,10 +23,6 @@ source_globs("include/*/*.c")
# Note *'s are removed when using fastcov
remove_source("/usr/*")
remove_source("*/include/sysc/*")
remove_source("*/V3ClkGater.cpp")
remove_source("*/V3ClkGater.h")
remove_source("*/V3GraphDfa.cpp")
remove_source("*/V3GraphDfa.h")
remove_source("*/V3Lexer_pregen.yy.cpp")
remove_source("*/V3PreLex_pregen.yy.cpp")
remove_source("*/verilog.c")

View File

@ -203,7 +203,6 @@ RAW_OBJS = \
V3Graph.o \
V3GraphAlg.o \
V3GraphAcyc.o \
V3GraphDfa.o \
V3GraphPathChecker.o \
V3GraphTest.o \
V3Hash.o \

View File

@ -50,8 +50,8 @@ public:
enum VertexType : uint8_t { VT_BLOCK, VT_BRANCH, VT_OUTPUT };
private:
string m_name; // Only used for .dot file generation
VertexType m_type; // Vertex type (BLOCK/BRANCH/OUTPUT)
const string m_name; // Only used for .dot file generation
const VertexType m_type; // Vertex type (BLOCK/BRANCH/OUTPUT)
string typestr() const { // "
switch (m_type) {
@ -108,9 +108,10 @@ protected:
}
break;
case LatchDetectGraphVertex::VT_BRANCH: // (AND of both sibling)
// A BRANCH vertex always has exactly 2 siblings
LatchDetectGraphVertex* ifp = castVertexp(vertexp->outBeginp()->top());
LatchDetectGraphVertex* elsp = castVertexp(vertexp->outBeginp()->outNextp()->top());
// A BRANCH vertex always has exactly 2 siblings
LatchDetectGraphVertex* const ifp = castVertexp(vertexp->outBeginp()->top());
LatchDetectGraphVertex* const elsp
= castVertexp(vertexp->outBeginp()->outNextp()->top());
result = latchCheckInternal(ifp) && latchCheckInternal(elsp);
break;
}
@ -151,7 +152,7 @@ public:
// Add a new output variable vertex and store a pointer to it in the user1 field of the
// variables AstNode
LatchDetectGraphVertex* addOutputVertex(AstVarRef* nodep) {
LatchDetectGraphVertex* outVertexp
LatchDetectGraphVertex* const outVertexp
= new LatchDetectGraphVertex{this, nodep->name(), LatchDetectGraphVertex::VT_OUTPUT};
nodep->varp()->user1p(outVertexp);
m_outputs.push_back(nodep);
@ -172,7 +173,7 @@ public:
void latchCheck(AstNode* nodep, bool latch_expected) {
bool latch_detected = false;
for (const auto& vrp : m_outputs) {
LatchDetectGraphVertex* vertp = castVertexp(vrp->varp()->user1p());
LatchDetectGraphVertex* const vertp = castVertexp(vrp->varp()->user1p());
vertp->user(true); // Identify the output vertex we are checking paths _to_
if (!latchCheckInternal(castVertexp(verticesBeginp()))) latch_detected = true;
if (latch_detected && !latch_expected) {
@ -262,7 +263,7 @@ public:
// Return a sentree in this scope that matches given sense list.
AstActive* activep = nullptr;
AstSenTree* activeSenp = m_activeSens.find(sensesp);
AstSenTree* const activeSenp = m_activeSens.find(sensesp);
if (activeSenp) {
const auto it = m_activeMap.find(activeSenp);
UASSERT(it != m_activeMap.end(), "Corrupt active map");
@ -271,7 +272,7 @@ public:
// Not found, form a new one
if (!activep) {
AstSenTree* newsenp = sensesp->cloneTree(false);
AstSenTree* const newsenp = sensesp->cloneTree(false);
activep = new AstActive(fl, "sequent", newsenp);
activep->sensesStorep(activep->sensesp());
UINFO(8, " New ACTIVE " << activep << endl);
@ -298,20 +299,20 @@ private:
// NODE STATE
// Input:
// AstVar::user1p // V2LatchGraphVertex* The vertex handling this node
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// STATE
LatchDetectGraph m_graph; // Graph used to detect latches in combo always
// VISITORS
virtual void visit(AstVarRef* nodep) {
AstVar* varp = nodep->varp();
const AstVar* const varp = nodep->varp();
if (nodep->access().isWriteOrRW() && varp->isSignal() && !varp->isUsedLoopIdx()) {
m_graph.addAssignment(nodep);
}
}
virtual void visit(AstNodeIf* nodep) {
if (!nodep->isBoundsCheck()) {
LatchDetectGraphVertex* parentp = m_graph.currentp();
LatchDetectGraphVertex* branchp = m_graph.addPathVertex(parentp, "BRANCH", true);
LatchDetectGraphVertex* const parentp = m_graph.currentp();
LatchDetectGraphVertex* const branchp = m_graph.addPathVertex(parentp, "BRANCH", true);
m_graph.addPathVertex(branchp, "IF");
iterateAndNextNull(nodep->ifsp());
m_graph.addPathVertex(branchp, "ELSE");
@ -340,9 +341,9 @@ public:
enum CheckType : uint8_t { CT_SEQ, CT_COMBO, CT_INITIAL, CT_LATCH };
private:
CheckType m_check; // Combo logic or other
AstNode* m_alwaysp; // Always we're under
AstNode* m_assignp = nullptr; // In assign
const CheckType m_check; // Combo logic or other
const AstNode* const m_alwaysp; // Always we're under
const AstNode* m_assignp = nullptr; // In assign
// VISITORS
virtual void visit(AstAssignDly* nodep) override {
if (m_check != CT_SEQ) {
@ -355,7 +356,7 @@ private:
} else if (m_check == CT_LATCH) {
// Suppress. Shouldn't matter that the interior of the latch races
} else if (!(VN_IS(nodep->lhsp(), VarRef)
&& VN_CAST(nodep->lhsp(), VarRef)->varp()->isLatched())) {
&& VN_AS(nodep->lhsp(), VarRef)->varp()->isLatched())) {
nodep->v3warn(COMBDLY, "Delayed assignments (<=) in non-clocked"
" (non flop or latch) block\n"
<< nodep->warnMore()
@ -363,8 +364,8 @@ private:
// Conversely, we could also suggest latches use delayed assignments, as
// recommended by Cliff Cummings?
}
AstNode* newp = new AstAssign(nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
nodep->rhsp()->unlinkFrBack());
AstNode* const newp = new AstAssign(nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
nodep->rhsp()->unlinkFrBack());
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
@ -377,7 +378,7 @@ private:
}
}
virtual void visit(AstVarRef* nodep) override {
AstVar* varp = nodep->varp();
const AstVar* const varp = nodep->varp();
if (m_check == CT_SEQ && m_assignp && !varp->isUsedLoopIdx() // Ignore loop indices
&& !varp->isTemp()) {
// Allow turning off warnings on the always, or the variable also
@ -437,29 +438,29 @@ private:
virtual void visit(AstInitial* nodep) override {
// Relink to IACTIVE, unless already under it
UINFO(4, " INITIAL " << nodep << endl);
ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL};
AstActive* wantactivep = m_namer.getIActive(nodep->fileline());
const ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL};
AstActive* const wantactivep = m_namer.getIActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
}
virtual void visit(AstAssignAlias* nodep) override {
// Relink to CACTIVE, unless already under it
UINFO(4, " ASSIGNW " << nodep << endl);
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
AstActive* const wantactivep = m_namer.getCActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
}
virtual void visit(AstAssignW* nodep) override {
// Relink to CACTIVE, unless already under it
UINFO(4, " ASSIGNW " << nodep << endl);
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
AstActive* const wantactivep = m_namer.getCActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
}
virtual void visit(AstCoverToggle* nodep) override {
// Relink to CACTIVE, unless already under it
UINFO(4, " COVERTOGGLE " << nodep << endl);
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
AstActive* const wantactivep = m_namer.getCActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
}
@ -470,7 +471,7 @@ private:
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return;
}
ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL};
const ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL};
if (!m_scopeFinalp) {
m_scopeFinalp = new AstCFunc(
nodep->fileline(), "_final_" + m_namer.scopep()->nameDotless(), m_namer.scopep());
@ -489,8 +490,7 @@ private:
// METHODS
void visitAlways(AstNode* nodep, AstSenTree* oldsensesp, VAlwaysKwd kwd) {
// Move always to appropriate ACTIVE based on its sense list
if (oldsensesp && oldsensesp->sensesp() && VN_IS(oldsensesp->sensesp(), SenItem)
&& VN_CAST(oldsensesp->sensesp(), SenItem)->isNever()) {
if (oldsensesp && oldsensesp->sensesp() && oldsensesp->sensesp()->isNever()) {
// Never executing. Kill it.
UASSERT_OBJ(!oldsensesp->sensesp()->nextp(), nodep,
"Never senitem should be alone, else the never should be eliminated.");
@ -540,14 +540,14 @@ private:
// Warn and/or convert any delayed assignments
if (combo && !sequent) {
ActiveLatchCheckVisitor latchvisitor{nodep, kwd};
const ActiveLatchCheckVisitor latchvisitor{nodep, kwd};
if (kwd == VAlwaysKwd::ALWAYS_LATCH) {
ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_LATCH};
ActiveDlyVisitor{nodep, ActiveDlyVisitor::CT_LATCH};
} else {
ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_COMBO};
ActiveDlyVisitor{nodep, ActiveDlyVisitor::CT_COMBO};
}
} else if (!combo && sequent) {
ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_SEQ};
ActiveDlyVisitor{nodep, ActiveDlyVisitor::CT_SEQ};
}
}
virtual void visit(AstAlways* nodep) override {
@ -578,7 +578,7 @@ private:
}
virtual void visit(AstSenItem* nodep) override {
if (nodep->varrefp()) {
if (AstBasicDType* basicp = nodep->varrefp()->dtypep()->basicp()) {
if (const AstBasicDType* const basicp = nodep->varrefp()->dtypep()->basicp()) {
if (basicp->isEventValue()) {
// Events need to be treated as active high so we only activate on event being
// 1
@ -620,6 +620,6 @@ public:
void V3Active::activeAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ ActiveVisitor visitor{nodep}; } // Destruct before checking
{ ActiveVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("active", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -42,22 +42,15 @@ private:
// AstNode::user() bool. True if processed
// Each call to V3Const::constify
// AstNode::user4() Used by V3Const::constify, called below
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// STATE
AstTopScope* m_topscopep = nullptr; // Top scope for adding sentrees under
SenTreeFinder m_finder; // Find global sentree's and add them
SenTreeFinder m_finder; // Find global sentree's / add them under the AstTopScope
// METHODS
VL_DEBUG_FUNC; // Declare debug()
// VISITORS
virtual void visit(AstTopScope* nodep) override {
m_topscopep = nodep;
m_finder.init(m_topscopep);
iterateChildren(nodep);
m_topscopep = nullptr;
}
virtual void visit(AstNodeModule* nodep) override {
// Create required actives and add to module
// We can start ordering at a module, or a scope
@ -68,10 +61,9 @@ private:
UINFO(4, " ACTIVE " << nodep << endl);
// Remove duplicate clocks and such; sensesp() may change!
V3Const::constifyExpensiveEdit(nodep);
AstSenTree* sensesp = nodep->sensesp();
AstSenTree* const sensesp = nodep->sensesp();
UASSERT_OBJ(sensesp, nodep, "nullptr");
if (sensesp->sensesp() && VN_IS(sensesp->sensesp(), SenItem)
&& VN_CAST(sensesp->sensesp(), SenItem)->isNever()) {
if (sensesp->sensesp() && sensesp->sensesp()->isNever()) {
// Never executing. Kill it.
UASSERT_OBJ(!sensesp->sensesp()->nextp(), nodep,
"Never senitem should be alone, else the never should be eliminated.");
@ -80,16 +72,16 @@ private:
}
// Copy combo tree to settlement tree with duplicated statements
if (sensesp->hasCombo()) {
AstSenTree* newsentreep = new AstSenTree(
AstSenTree* const newsentreep = new AstSenTree(
nodep->fileline(), new AstSenItem(nodep->fileline(), AstSenItem::Settle()));
AstActive* newp = new AstActive(nodep->fileline(), "settle", newsentreep);
AstActive* const newp = new AstActive(nodep->fileline(), "settle", newsentreep);
newp->sensesStorep(newsentreep);
if (nodep->stmtsp()) newp->addStmtsp(nodep->stmtsp()->cloneTree(true));
nodep->addNextHere(newp);
}
// Move the SENTREE for each active up to the global level.
// This way we'll easily see what clock domains are identical
AstSenTree* wantp = m_finder.getSenTree(sensesp);
AstSenTree* const wantp = m_finder.getSenTree(sensesp);
UINFO(4, " lookdone\n");
if (wantp != sensesp) {
// Move the active's contents to the other active
@ -136,6 +128,6 @@ public:
void V3ActiveTop::activeTopAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ ActiveTopVisitor visitor{nodep}; } // Destruct before checking
{ ActiveTopVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("activetop", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -20,7 +20,6 @@
#include "V3Global.h"
#include "V3Assert.h"
#include "V3Ast.h"
#include "V3GraphDfa.h"
#include "V3Stats.h"
//######################################################################
@ -31,11 +30,11 @@ private:
// NODE STATE/TYPES
// Cleared on netlist
// AstNode::user() -> bool. True if processed
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// STATE
AstNodeModule* m_modp = nullptr; // Last module
AstBegin* m_beginp = nullptr; // Last begin
const AstBegin* m_beginp = nullptr; // Last begin
unsigned m_monitorNum = 0; // Global $monitor numbering (not per module)
AstVar* m_monitorNumVarp = nullptr; // $monitor number variable
AstVar* m_monitorOffVarp = nullptr; // $monitoroff variable
@ -56,14 +55,14 @@ private:
nodep->displayType(AstDisplayType::DT_WRITE);
nodep->fmtp()->text(assertDisplayMessage(nodep, prefix, nodep->fmtp()->text()));
// cppcheck-suppress nullPointer
AstNode* timenewp = new AstTime(nodep->fileline(), m_modp->timeunit());
if (AstNode* timesp = nodep->fmtp()->exprsp()) {
AstNode* const timenewp = new AstTime(nodep->fileline(), m_modp->timeunit());
if (AstNode* const timesp = nodep->fmtp()->exprsp()) {
timesp->unlinkFrBackWithNext();
timenewp->addNext(timesp);
}
nodep->fmtp()->addExprsp(timenewp);
if (!nodep->fmtp()->scopeNamep() && nodep->fmtp()->formatScopeTracking()) {
nodep->fmtp()->scopeNamep(new AstScopeName(nodep->fileline()));
nodep->fmtp()->scopeNamep(new AstScopeName{nodep->fileline(), true});
}
}
AstVarRef* newMonitorNumVarRefp(AstNode* nodep, VAccess access) {
@ -89,8 +88,8 @@ private:
AstNode* newIfAssertOn(AstNode* nodep, bool force) {
// Add a internal if to check assertions are on.
// Don't make this a AND term, as it's unlikely to need to test this.
FileLine* fl = nodep->fileline();
AstNode* newp = new AstIf(
FileLine* const fl = nodep->fileline();
AstNode* const newp = new AstIf(
fl,
(force ? new AstConst(fl, AstConst::BitTrue())
: // If assertions are off, have constant propagation rip them out later
@ -106,10 +105,10 @@ private:
AstNode* newFireAssertUnchecked(AstNode* nodep, const string& message) {
// Like newFireAssert() but omits the asserts-on check
AstDisplay* dispp = new AstDisplay(nodep->fileline(), AstDisplayType::DT_ERROR, message,
nullptr, nullptr);
AstDisplay* const dispp = new AstDisplay(nodep->fileline(), AstDisplayType::DT_ERROR,
message, nullptr, nullptr);
dispp->fmtp()->timeunit(m_modp->timeunit());
AstNode* bodysp = dispp;
AstNode* const bodysp = dispp;
replaceDisplay(dispp, "%%Error"); // Convert to standard DISPLAY format
bodysp->addNext(new AstStop(nodep->fileline(), true));
return bodysp;
@ -124,8 +123,8 @@ private:
void newPslAssertion(AstNodeCoverOrAssert* nodep, AstNode* failsp) {
if (m_beginp && nodep->name() == "") nodep->name(m_beginp->name());
AstNode* propp = nodep->propp()->unlinkFrBackWithNext();
AstSenTree* sentreep = nodep->sentreep();
AstNode* const propp = nodep->propp()->unlinkFrBackWithNext();
AstSenTree* const sentreep = nodep->sentreep();
const string& message = nodep->name();
AstNode* passsp = nodep->passsp();
if (passsp) passsp->unlinkFrBackWithNext();
@ -141,13 +140,13 @@ private:
AstNode* bodysp = nullptr;
bool selfDestruct = false;
AstIf* ifp = nullptr;
if (AstCover* snodep = VN_CAST(nodep, Cover)) {
if (const AstCover* const snodep = VN_CAST(nodep, Cover)) {
++m_statCover;
if (!v3Global.opt.coverageUser()) {
selfDestruct = true;
} else {
// V3Coverage assigned us a bucket to increment.
AstCoverInc* covincp = VN_CAST(snodep->coverincp(), CoverInc);
AstCoverInc* const covincp = VN_AS(snodep->coverincp(), CoverInc);
UASSERT_OBJ(covincp, snodep, "Missing AstCoverInc under assertion");
covincp->unlinkFrBackWithNext(); // next() might have AstAssign for trace
if (message != "") covincp->declp()->comment(message);
@ -199,13 +198,13 @@ private:
virtual void visit(AstIf* nodep) override {
if (nodep->user1SetOnce()) return;
if (nodep->uniquePragma() || nodep->unique0Pragma()) {
AstNodeIf* ifp = nodep;
const AstNodeIf* ifp = nodep;
AstNode* propp = nullptr;
bool hasDefaultElse = false;
do {
// If this statement ends with 'else if', then nextIf will point to the
// nextIf statement. Otherwise it will be null.
AstNodeIf* nextifp = dynamic_cast<AstNodeIf*>(ifp->elsesp());
const AstNodeIf* const nextifp = dynamic_cast<AstNodeIf*>(ifp->elsesp());
iterateAndNextNull(ifp->condp());
// Recurse into the true case.
@ -217,7 +216,7 @@ private:
}
// Build a bitmask of the true predicates
AstNode* predp = ifp->condp()->cloneTree(false);
AstNode* const predp = ifp->condp()->cloneTree(false);
if (propp) {
propp = new AstConcat(nodep->fileline(), predp, propp);
} else {
@ -230,7 +229,7 @@ private:
ifp = nextifp;
} while (ifp);
AstNode* newifp = nodep->cloneTree(false);
AstNode* const newifp = nodep->cloneTree(false);
const bool allow_none = nodep->unique0Pragma();
// Empty case means no property
@ -238,10 +237,11 @@ private:
// Note: if this ends with an 'else', then we don't need to validate that one of the
// predicates evaluates to true.
AstNode* ohot = ((allow_none || hasDefaultElse)
? static_cast<AstNode*>(new AstOneHot0(nodep->fileline(), propp))
: static_cast<AstNode*>(new AstOneHot(nodep->fileline(), propp)));
AstIf* checkifp
AstNode* const ohot
= ((allow_none || hasDefaultElse)
? static_cast<AstNode*>(new AstOneHot0(nodep->fileline(), propp))
: static_cast<AstNode*>(new AstOneHot(nodep->fileline(), propp)));
AstIf* const checkifp
= new AstIf(nodep->fileline(), new AstLogNot(nodep->fileline(), ohot),
newFireAssert(nodep, "'unique if' statement violated"), newifp);
checkifp->branchPred(VBranchPred::BP_UNLIKELY);
@ -258,7 +258,7 @@ private:
if (!nodep->user1SetOnce()) {
bool has_default = false;
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
itemp = VN_AS(itemp->nextp(), CaseItem)) {
if (itemp->isDefault()) has_default = true;
}
if (nodep->fullPragma() || nodep->priorityPragma()) {
@ -279,10 +279,10 @@ private:
} else {
AstNode* propp = nullptr;
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
itemp = VN_AS(itemp->nextp(), CaseItem)) {
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondp->nextp()) {
AstNode* onep;
if (AstInsideRange* rcondp = VN_CAST(icondp, InsideRange)) {
if (AstInsideRange* const rcondp = VN_CAST(icondp, InsideRange)) {
onep = rcondp->newAndFromInside(nodep->exprp(),
rcondp->lhsp()->cloneTree(true),
rcondp->rhsp()->cloneTree(true));
@ -306,11 +306,11 @@ private:
if (!propp) propp = new AstConst(nodep->fileline(), AstConst::BitFalse());
const bool allow_none = has_default || nodep->unique0Pragma();
AstNode* ohot
AstNode* const ohot
= (allow_none
? static_cast<AstNode*>(new AstOneHot0(nodep->fileline(), propp))
: static_cast<AstNode*>(new AstOneHot(nodep->fileline(), propp)));
AstIf* ifp = new AstIf(
AstIf* const ifp = new AstIf(
nodep->fileline(), new AstLogNot(nodep->fileline(), ohot),
newFireAssert(nodep,
"synthesis parallel_case, but multiple matches found"),
@ -329,22 +329,22 @@ private:
if (nodep->ticksp()) {
UASSERT_OBJ(VN_IS(nodep->ticksp(), Const), nodep,
"Expected constant ticks, checked in V3Width");
ticks = VN_CAST(nodep->ticksp(), Const)->toUInt();
ticks = VN_AS(nodep->ticksp(), Const)->toUInt();
}
UASSERT_OBJ(ticks >= 1, nodep, "0 tick should have been checked in V3Width");
AstNode* inp = nodep->exprp()->unlinkFrBack();
AstVar* invarp = nullptr;
AstSenTree* sentreep = nodep->sentreep();
AstSenTree* const sentreep = nodep->sentreep();
sentreep->unlinkFrBack();
AstAlways* alwaysp
AstAlways* const alwaysp
= new AstAlways(nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, nullptr);
m_modp->addStmtp(alwaysp);
for (uint32_t i = 0; i < ticks; ++i) {
AstVar* outvarp = new AstVar(nodep->fileline(), AstVarType::MODULETEMP,
"_Vpast_" + cvtToStr(m_modPastNum++) + "_" + cvtToStr(i),
inp->dtypep());
AstVar* const outvarp = new AstVar(
nodep->fileline(), AstVarType::MODULETEMP,
"_Vpast_" + cvtToStr(m_modPastNum++) + "_" + cvtToStr(i), inp->dtypep());
m_modp->addStmtp(outvarp);
AstNode* assp = new AstAssignDly(
AstNode* const assp = new AstAssignDly(
nodep->fileline(), new AstVarRef(nodep->fileline(), outvarp, VAccess::WRITE), inp);
alwaysp->addStmtp(assp);
// if (debug() >= 9) assp->dumpTree(cout, "-ass: ");
@ -378,15 +378,15 @@ private:
new AstConst{fl, monNum}};
nodep->replaceWith(newsetp);
// Add "always_comb if (__VmonitorOn && __VmonitorNum==N) $display(...);"
AstNode* stmtsp = nodep;
AstIf* ifp = new AstIf{
AstNode* const stmtsp = nodep;
AstIf* const ifp = new AstIf{
fl,
new AstLogAnd{fl, new AstLogNot{fl, newMonitorOffVarRefp(nodep, VAccess::READ)},
new AstEq{fl, new AstConst{fl, monNum},
newMonitorNumVarRefp(nodep, VAccess::READ)}},
stmtsp, nullptr};
ifp->branchPred(VBranchPred::BP_UNLIKELY);
AstNode* newp = new AstAlwaysPostponed{fl, ifp};
AstNode* const newp = new AstAlwaysPostponed{fl, ifp};
m_modp->addStmtp(newp);
} else if (nodep->displayType() == AstDisplayType::DT_STROBE) {
nodep->displayType(AstDisplayType::DT_DISPLAY);
@ -401,10 +401,11 @@ private:
new AstConst{fl, AstConst::BitTrue{}}};
nodep->replaceWith(newsetp);
// Add "always_comb if (__Vstrobe) begin $display(...); __Vstrobe = '0; end"
AstNode* stmtsp = nodep;
AstIf* ifp = new AstIf{fl, new AstVarRef{fl, varp, VAccess::READ}, stmtsp, nullptr};
AstNode* const stmtsp = nodep;
AstIf* const ifp
= new AstIf{fl, new AstVarRef{fl, varp, VAccess::READ}, stmtsp, nullptr};
ifp->branchPred(VBranchPred::BP_UNLIKELY);
AstNode* newp = new AstAlwaysPostponed{fl, ifp};
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);
@ -474,6 +475,6 @@ public:
void V3Assert::assertAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ AssertVisitor visitor{nodep}; } // Destruct before checking
{ AssertVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("assert", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -97,10 +97,10 @@ private:
virtual void visit(AstFell* nodep) override {
if (nodep->sentreep()) return; // Already processed
iterateChildren(nodep);
FileLine* fl = nodep->fileline();
FileLine* const fl = nodep->fileline();
AstNode* exprp = nodep->exprp()->unlinkFrBack();
if (exprp->width() > 1) exprp = new AstSel(fl, exprp, 0, 1);
AstNode* past = new AstPast(fl, exprp, nullptr);
AstNode* const past = new AstPast(fl, exprp, nullptr);
past->dtypeFrom(exprp);
exprp = new AstAnd(fl, past, new AstNot(fl, exprp->cloneTree(false)));
exprp->dtypeSetBit();
@ -116,10 +116,10 @@ private:
virtual void visit(AstRose* nodep) override {
if (nodep->sentreep()) return; // Already processed
iterateChildren(nodep);
FileLine* fl = nodep->fileline();
FileLine* const fl = nodep->fileline();
AstNode* exprp = nodep->exprp()->unlinkFrBack();
if (exprp->width() > 1) exprp = new AstSel(fl, exprp, 0, 1);
AstNode* past = new AstPast(fl, exprp, nullptr);
AstNode* const past = new AstPast(fl, exprp, nullptr);
past->dtypeFrom(exprp);
exprp = new AstAnd(fl, new AstNot(fl, past), exprp->cloneTree(false));
exprp->dtypeSetBit();
@ -130,9 +130,9 @@ private:
virtual void visit(AstStable* nodep) override {
if (nodep->sentreep()) return; // Already processed
iterateChildren(nodep);
FileLine* fl = nodep->fileline();
FileLine* const fl = nodep->fileline();
AstNode* exprp = nodep->exprp()->unlinkFrBack();
AstNode* past = new AstPast(fl, exprp, nullptr);
AstNode* const past = new AstPast(fl, exprp, nullptr);
past->dtypeFrom(exprp);
exprp = new AstEq(fl, past, exprp->cloneTree(false));
exprp->dtypeSetBit();
@ -144,15 +144,15 @@ private:
virtual void visit(AstImplication* nodep) override {
if (nodep->sentreep()) return; // Already processed
FileLine* fl = nodep->fileline();
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
FileLine* const fl = nodep->fileline();
AstNode* const rhsp = nodep->rhsp()->unlinkFrBack();
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
if (m_disablep) lhsp = new AstAnd(fl, new AstNot(fl, m_disablep), lhsp);
AstNode* past = new AstPast(fl, lhsp, nullptr);
AstNode* const past = new AstPast(fl, lhsp, nullptr);
past->dtypeFrom(lhsp);
AstNode* exprp = new AstOr(fl, new AstNot(fl, past), rhsp);
AstNode* const exprp = new AstOr(fl, new AstNot(fl, past), rhsp);
exprp->dtypeSetBit();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep));
@ -205,6 +205,6 @@ public:
void V3AssertPre::assertPreAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ AssertPreVisitor visitor{nodep}; } // Destruct before checking
{ AssertPreVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("assertpre", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -95,7 +95,7 @@ AstNode* AstNode::abovep() const {
// Avoid supporting at other locations as would require walking
// list which is likely to cause performance issues.
UASSERT_OBJ(!m_nextp || firstAbovep(), this, "abovep() not allowed when in midlist");
const AstNode* firstp = firstAbovep() ? this : m_headtailp;
const AstNode* const firstp = firstAbovep() ? this : m_headtailp;
return firstp->backp();
}
@ -277,8 +277,8 @@ AstNode* AstNode::addNext(AstNode* nodep, AstNode* newp) {
oldtailp->m_nextp = newp;
newp->m_backp = oldtailp;
// New tail needs the head
AstNode* newtailp = newp->m_headtailp;
AstNode* headp = oldtailp->m_headtailp;
AstNode* const newtailp = newp->m_headtailp;
AstNode* const headp = oldtailp->m_headtailp;
oldtailp->m_headtailp = nullptr; // May be written again as new head
newp->m_headtailp = nullptr; // May be written again as new tail
newtailp->m_headtailp = headp;
@ -305,11 +305,11 @@ void AstNode::addNextHere(AstNode* newp) {
debugTreeChange(newp, "-addHereNew: ", __LINE__, true);
newp->editCountInc();
AstNode* addlastp = newp->m_headtailp; // Last node in list to be added
AstNode* const addlastp = newp->m_headtailp; // Last node in list to be added
UASSERT(!addlastp->m_nextp, "Headtailp tail isn't at the tail");
// Forward links
AstNode* oldnextp = this->m_nextp;
AstNode* const oldnextp = this->m_nextp;
this->m_nextp = newp;
addlastp->m_nextp = oldnextp; // Perhaps null if 'this' is not list
@ -318,7 +318,7 @@ void AstNode::addNextHere(AstNode* newp) {
newp->m_backp = this;
// Head/tail
AstNode* oldheadtailp = this->m_headtailp;
AstNode* const oldheadtailp = this->m_headtailp;
// (!oldheadtailp) // this was&is middle of list
// (oldheadtailp==this && !oldnext)// this was head AND tail (one node long list)
// (oldheadtailp && oldnextp) // this was&is head of list of not just one node, not
@ -455,10 +455,10 @@ void AstNRelinker::dump(std::ostream& str) const {
AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
debugTreeChange(this, "-unlinkWNextThs: ", __LINE__, true);
AstNode* oldp = this;
AstNode* const oldp = this;
UASSERT(oldp->m_backp, "Node has no back, already unlinked?");
oldp->editCountInc();
AstNode* backp = oldp->m_backp;
AstNode* const backp = oldp->m_backp;
if (linkerp) {
linkerp->m_oldp = oldp;
linkerp->m_backp = backp;
@ -487,7 +487,7 @@ AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
AstNode* oldtailp = oldp;
while (oldtailp->m_nextp) oldtailp = oldtailp->m_nextp;
// Create new head/tail of old list
AstNode* oldheadp = oldtailp->m_headtailp;
AstNode* const oldheadp = oldtailp->m_headtailp;
oldheadp->m_headtailp = oldp->m_backp;
oldheadp->m_headtailp->m_headtailp = oldheadp;
// Create new head/tail of extracted list
@ -515,10 +515,10 @@ AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
AstNode* AstNode::unlinkFrBack(AstNRelinker* linkerp) {
debugTreeChange(this, "-unlinkFrBkThs: ", __LINE__, true);
AstNode* oldp = this;
AstNode* const oldp = this;
UASSERT(oldp->m_backp, "Node has no back, already unlinked?");
oldp->editCountInc();
AstNode* backp = oldp->m_backp;
AstNode* const backp = oldp->m_backp;
if (linkerp) {
linkerp->m_oldp = oldp;
linkerp->m_backp = backp;
@ -560,7 +560,7 @@ AstNode* AstNode::unlinkFrBack(AstNRelinker* linkerp) {
this->v3fatalSrc("Unlink of node with back not pointing to it.");
}
if (oldp->m_nextp) {
AstNode* newheadp = oldp->m_nextp;
AstNode* const newheadp = oldp->m_nextp;
newheadp->m_backp = backp;
newheadp->m_headtailp = oldp->m_headtailp;
newheadp->m_headtailp->m_headtailp = newheadp;
@ -582,7 +582,7 @@ void AstNode::relink(AstNRelinker* linkerp) {
UINFO(0, " EDIT: relink: ");
dumpPtrs();
}
AstNode* newp = this;
AstNode* const newp = this;
UASSERT(linkerp && linkerp->m_backp, "Need non-empty linker");
UASSERT(!newp->backp(), "New node already linked?");
newp->editCountInc();
@ -592,7 +592,7 @@ void AstNode::relink(AstNRelinker* linkerp) {
cout << endl;
}
AstNode* backp = linkerp->m_backp;
AstNode* const backp = linkerp->m_backp;
debugTreeChange(this, "-relinkNew: ", __LINE__, true);
debugTreeChange(backp, "-relinkTre: ", __LINE__, true);
@ -631,10 +631,10 @@ void AstNode::relinkOneLink(AstNode*& pointpr, // Ref to pointer that gets set
// Likewise there may be a old list.
// Insert the whole old list following the new node's list.
// Thus a unlink without next, followed by relink, gives the same list.
AstNode* newlistlastp = newp->m_headtailp;
AstNode* const newlistlastp = newp->m_headtailp;
UASSERT_OBJ(!(newlistlastp->m_nextp && newlistlastp != newp), newp,
"Headtailp tail isn't at the tail");
AstNode* oldlistlastp = pointpr->m_headtailp;
AstNode* const oldlistlastp = pointpr->m_headtailp;
UASSERT_OBJ(!(oldlistlastp->m_nextp && oldlistlastp != pointpr), newp,
"Old headtailp tail isn't at the tail");
// Next links
@ -671,7 +671,7 @@ void AstNode::swapWith(AstNode* bp) {
AstNode* AstNode::cloneTreeIter() {
// private: Clone single node and children
AstNode* newp = this->clone();
AstNode* const newp = this->clone();
if (this->m_op1p) newp->op1p(this->m_op1p->cloneTreeIterList());
if (this->m_op2p) newp->op2p(this->m_op2p->cloneTreeIterList());
if (this->m_op3p) newp->op3p(this->m_op3p->cloneTreeIterList());
@ -688,7 +688,7 @@ AstNode* AstNode::cloneTreeIterList() {
AstNode* newtailp = nullptr;
// Audited to make sure this is never nullptr
for (AstNode* oldp = this; oldp; oldp = oldp->m_nextp) {
AstNode* newp = oldp->cloneTreeIter();
AstNode* const newp = oldp->cloneTreeIter();
newp->m_headtailp = nullptr;
newp->m_backp = newtailp;
if (newtailp) newtailp->m_nextp = newp;
@ -777,14 +777,14 @@ void AstNode::deleteTree() {
#ifdef VL_LEAK_CHECKS
void* AstNode::operator new(size_t size) {
// Optimization note: Aligning to cache line is a loss, due to lost packing
AstNode* objp = static_cast<AstNode*>(::operator new(size));
const AstNode* const objp = static_cast<AstNode*>(::operator new(size));
V3Broken::addNewed(objp);
return objp;
}
void AstNode::operator delete(void* objp, size_t size) {
if (!objp) return;
AstNode* nodep = static_cast<AstNode*>(objp);
const AstNode* const nodep = static_cast<AstNode*>(objp);
V3Broken::deleted(nodep);
::operator delete(objp);
}
@ -877,7 +877,7 @@ void AstNode::iterateAndNextConst(AstNVisitor& v) {
// Keep following the current list even if edits change it
AstNode* nodep = this;
do {
AstNode* nnextp = nodep->m_nextp;
AstNode* const nnextp = nodep->m_nextp;
ASTNODE_PREFETCH(nnextp);
nodep->accept(v);
nodep = nnextp;
@ -898,7 +898,7 @@ AstNode* AstNode::iterateSubtreeReturnEdits(AstNVisitor& v) {
} else if (!nodep->backp()) {
// Calling on standalone tree; insert a shim node so we can keep
// track, then delete it on completion
AstBegin* 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
@ -994,8 +994,8 @@ void AstNode::checkTreeIter(AstNode* backp) {
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* headp = this;
AstNode* tailp = this;
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,
@ -1143,7 +1143,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump, boo
checkTree();
// Broken isn't part of check tree because it can munge iterp's
// set by other steps if it is called in the middle of other operations
if (AstNetlist* netp = VN_CAST(this, Netlist)) V3Broken::brokenAll(netp);
if (AstNetlist* const netp = VN_CAST(this, Netlist)) V3Broken::brokenAll(netp);
}
}
@ -1164,7 +1164,7 @@ string AstNode::locationStr() const {
return ""; // LCOV_EXCL_LINE
}
const AstScope* scopep;
if ((scopep = VN_CAST_CONST(backp, Scope))) {
if ((scopep = VN_CAST(backp, Scope))) {
// The design is flattened and there are no useful scopes
// This is probably because of inlining
if (scopep->isTop()) break;
@ -1178,10 +1178,10 @@ string AstNode::locationStr() const {
while (backp) {
const AstModule* modp;
const AstNodeVarRef* nvrp;
if ((modp = VN_CAST_CONST(backp, Module)) && !modp->hierName().empty()) {
if ((modp = VN_CAST(backp, Module)) && !modp->hierName().empty()) {
str += modp->hierName();
return str;
} else if ((nvrp = VN_CAST_CONST(backp, NodeVarRef))) {
} else if ((nvrp = VN_CAST(backp, NodeVarRef))) {
const string prettyName = nvrp->prettyName();
// VarRefs have not been flattened yet and do not contain location information
if (prettyName != nvrp->name()) {
@ -1276,9 +1276,9 @@ AstNodeDType* AstNode::findVoidDType() const {
}
//######################################################################
// AstNVisitor
// AstNDeleter
void AstNVisitor::doDeletes() {
for (AstNode* nodep : m_deleteps) nodep->deleteTree();
void AstNDeleter::doDeletes() {
for (AstNode* const nodep : m_deleteps) nodep->deleteTree();
m_deleteps.clear();
}

View File

@ -56,23 +56,26 @@ using MTaskIdSet = std::set<int>; // Set of mtaskIds for Var sorting
// For broken() function, return error string if a base of this class has a match
#define BROKEN_BASE_RTN(test) \
do { \
const char* reasonp = (test); \
const char* const reasonp = (test); \
if (VL_UNCOVERABLE(reasonp)) return reasonp; \
} while (false)
// (V)erilator (N)ode is: Returns true iff AstNode is of the given AstNode subtype, and not
// nullptr.
#define VN_IS(nodep, nodetypename) (AstNode::privateIs<Ast##nodetypename>(nodep))
// (V)erilator (N)ode is: Returns true if and only if AstNode is of the given AstNode subtype,
// and not nullptr.
#define VN_IS(nodep, nodetypename) (AstNode::privateIs<Ast##nodetypename, decltype(nodep)>(nodep))
// (V)erilator (N)ode cast: More efficient but otherwise same as dynamic_cast, use this instead.
// Cast to given type if node is of such type, otherwise returns nullptr.
#define VN_CAST(nodep, nodetypename) (AstNode::privateCast<Ast##nodetypename>(nodep))
#define VN_CAST_CONST(nodep, nodetypename) (AstNode::privateCastConst<Ast##nodetypename>(nodep))
// (V)erilator (N)ode cast: Similar to dynamic_cast, but more efficient, use this instead.
// Cast to given type if node is of such type, otherwise returns nullptr. If 'nodep' is nullptr,
// return nullptr. Pointer constness is preserved, i.e.: given a 'const AstNode*',
// a 'const Ast<nodetypename>*' is returned.
#define VN_CAST(nodep, nodetypename) \
(AstNode::privateCast<Ast##nodetypename, decltype(nodep)>(nodep))
// (V)erilator (N)ode as: Assert node is of given type then cast to that type. Node can be nullptr.
// Use this to downcast instead of VN_CAST when you know the true type of the node.
#define VN_AS(nodep, nodetypename) (AstNode::privateAs<Ast##nodetypename>(nodep))
#define VN_AS_CONST(nodep, nodetypename) (AstNode::privateAsConst<Ast##nodetypename>(nodep))
// (V)erilator (N)ode as: Assert node is of given type then cast to that type. Use this to
// downcast instead of VN_CAST when you know the true type of the node. If 'nodep' is nullptr,
// return nullptr. Pointer constness is preserved, i.e.: given a 'const AstNode*', a 'const
// Ast<nodetypename>*' is returned.
#define VN_AS(nodep, nodetypename) (AstNode::privateAs<Ast##nodetypename, decltype(nodep)>(nodep))
// (V)erilator (N)ode deleted: Pointer to deleted AstNode (for assertions only)
#define VN_DELETED(nodep) VL_UNLIKELY((vluint64_t)(nodep) == 0x1)
@ -501,7 +504,8 @@ public:
}
bool isUnsigned() const {
return m_e == CHANDLE || m_e == EVENTVALUE || m_e == STRING || m_e == SCOPEPTR
|| m_e == CHARPTR || m_e == UINT32 || m_e == UINT64;
|| m_e == CHARPTR || m_e == UINT32 || m_e == UINT64 || m_e == BIT || m_e == LOGIC
|| m_e == TIME;
}
bool isFourstate() const {
return m_e == INTEGER || m_e == LOGIC || m_e == LOGIC_IMPLICIT || m_e == TIME;
@ -514,9 +518,6 @@ public:
return (m_e == BIT || m_e == BYTE || m_e == INT || m_e == INTEGER || m_e == LOGIC
|| m_e == LONGINT || m_e == SHORTINT || m_e == UINT32 || m_e == UINT64);
}
bool isSloppy() const { // Don't be as anal about width warnings
return !(m_e == LOGIC || m_e == BIT);
}
bool isBitLogic() const { // Bit/logic vector types; can form a packed array
return (m_e == LOGIC || m_e == BIT);
}
@ -1007,7 +1008,7 @@ public:
// MEMBERS
void init(int hi, int lo, bool littleEndian) {
if (lo > hi) {
int t = hi;
const int t = hi;
hi = lo;
lo = t;
}
@ -1026,9 +1027,6 @@ public:
int hiMaxSelect() const {
return (lo() < 0 ? hi() - lo() : hi());
} // Maximum value a [] select may index
bool representableByWidth() const { // Could be represented by just width=1, or [width-1:0]
return (!m_ranged || (m_right == 0 && m_left >= 1));
}
void dump(std::ostream& str) const {
if (ranged()) {
str << "[" << left() << ":" << right() << "]";
@ -1079,11 +1077,11 @@ inline std::ostream& operator<<(std::ostream& os, const VUseType& rhs) {
class VBasicTypeKey final {
public:
int m_width; // From AstNodeDType: Bit width of operation
int m_widthMin; // From AstNodeDType: If unsized, bitwidth of minimum implementation
VSigning m_numeric; // From AstNodeDType: Node is signed
AstBasicDTypeKwd m_keyword; // From AstBasicDType: What keyword created basic type
VNumRange m_nrange; // From AstBasicDType: Numeric msb/lsb (if non-opaque keyword)
const int m_width; // From AstNodeDType: Bit width of operation
const int m_widthMin; // From AstNodeDType: If unsized, bitwidth of minimum implementation
const VSigning m_numeric; // From AstNodeDType: Node is signed
const AstBasicDTypeKwd m_keyword; // From AstBasicDType: What keyword created basic type
const VNumRange m_nrange; // From AstBasicDType: Numeric msb/lsb (if non-opaque keyword)
bool operator==(const VBasicTypeKey& rhs) const {
return m_width == rhs.m_width && m_widthMin == rhs.m_widthMin && m_numeric == rhs.m_numeric
&& m_keyword == rhs.m_keyword && m_nrange == rhs.m_nrange;
@ -1248,31 +1246,39 @@ public:
// clang-format on
//######################################################################
// AstNVisitor -- Allows new functions to be called on each node
// type without changing the base classes. See "Modern C++ Design".
// Node deleter, deletes all enqueued AstNode* on destruction, or when
// explicitly told to do so. This is useful when the deletion of removed
// nodes needs to be deferred to a later time, because pointers to the
// removed nodes might still exist.
class AstNVisitor VL_NOT_FINAL {
private:
class AstNDeleter VL_NOT_FINAL {
// MEMBERS
std::vector<AstNode*> m_deleteps; // Nodes to delete when doDeletes() called
protected:
friend class AstNode;
std::vector<AstNode*> m_deleteps; // Nodes to delete
public:
// METHODS
/// At the end of the visitor (or doDeletes()), delete this pushed node
/// along with all children and next(s). This is often better to use
/// than an immediate deleteTree, as any pointers into this node will
/// persist for the lifetime of the visitor
// Enqueue node for deletion on next 'doDelete' (or destruction)
void pushDeletep(AstNode* nodep) {
UASSERT_STATIC(nodep, "Cannot delete nullptr node");
m_deleteps.push_back(nodep);
}
/// Call deleteTree on all previously pushDeletep()'ed nodes
// Delete all previously pushed nodes (by callint deleteTree)
void doDeletes();
// Do the deletions on destruction
virtual ~AstNDeleter() { doDeletes(); }
};
//######################################################################
// AstNVisitor -- Allows new functions to be called on each node
// type without changing the base classes. See "Modern C++ Design".
class AstNVisitor VL_NOT_FINAL : public AstNDeleter {
friend class AstNode;
public:
virtual ~AstNVisitor() { doDeletes(); }
/// Call visit()s on nodep
void iterate(AstNode* nodep);
/// Call visit()s on nodep
@ -1847,28 +1853,54 @@ private:
// For internal use only.
template <typename T> inline static bool privateTypeTest(const AstNode* nodep);
template <typename TargetType, typename DeclType> constexpr static bool uselessCast() {
using NonRef = typename std::remove_reference<DeclType>::type;
using NonPtr = typename std::remove_pointer<NonRef>::type;
using NonCV = typename std::remove_cv<NonPtr>::type;
return std::is_base_of<TargetType, NonCV>::value;
}
template <typename TargetType, typename DeclType> constexpr static bool impossibleCast() {
using NonRef = typename std::remove_reference<DeclType>::type;
using NonPtr = typename std::remove_pointer<NonRef>::type;
using NonCV = typename std::remove_cv<NonPtr>::type;
return !std::is_base_of<NonCV, TargetType>::value;
}
public:
// For use via the VN_IS macro only
template <typename T> inline static bool privateIs(const AstNode* nodep) {
template <typename T, typename E> inline static bool privateIs(const AstNode* nodep) {
static_assert(!uselessCast<T, E>(), "Unnecessary VN_IS, node known to have target type.");
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_IS, node cannot be this type.");
return nodep && privateTypeTest<T>(nodep);
}
// For use via the VN_CAST macro only
template <typename T> inline static T* privateCast(AstNode* nodep) {
return privateIs<T>(nodep) ? reinterpret_cast<T*>(nodep) : nullptr;
template <typename T, typename E> inline static T* privateCast(AstNode* nodep) {
static_assert(!uselessCast<T, E>(),
"Unnecessary VN_CAST, node known to have target type.");
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_CAST, node cannot be this type.");
return nodep && privateTypeTest<T>(nodep) ? reinterpret_cast<T*>(nodep) : nullptr;
}
// For use via the VN_CAST_CONST macro only
template <typename T> inline static const T* privateCastConst(const AstNode* nodep) {
return privateIs<T>(nodep) ? reinterpret_cast<const T*>(nodep) : nullptr;
template <typename T, typename E> inline static const T* privateCast(const AstNode* nodep) {
static_assert(!uselessCast<T, E>(),
"Unnecessary VN_CAST, node known to have target type.");
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_CAST, node cannot be this type.");
return nodep && privateTypeTest<T>(nodep) ? reinterpret_cast<const T*>(nodep) : nullptr;
}
// For use via the VN_AS macro only
template <typename T> inline static T* privateAs(AstNode* nodep) {
template <typename T, typename E> inline static T* privateAs(AstNode* nodep) {
static_assert(!uselessCast<T, E>(), "Unnecessary VN_AS, node known to have target type.");
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_AS, node cannot be this type.");
UASSERT_OBJ(!nodep || privateTypeTest<T>(nodep), nodep,
"AstNode is not of expected type, but instead has type '" << nodep->typeName()
<< "'");
return reinterpret_cast<T*>(nodep);
}
// For use via the VN_AS_CONST macro only
template <typename T> inline static const T* privateAsConst(const AstNode* nodep) {
template <typename T, typename E> inline static const T* privateAs(const AstNode* nodep) {
static_assert(!uselessCast<T, E>(), "Unnecessary VN_AS, node known to have target type.");
static_assert(!impossibleCast<T, E>(), "Unnecessary VN_AS, node cannot be this type.");
UASSERT_OBJ(!nodep || privateTypeTest<T>(nodep), nodep,
"AstNode is not of expected type, but instead has type '" << nodep->typeName()
<< "'");
@ -1922,7 +1954,7 @@ public:
virtual bool cleanOut() const = 0; // True if output has extra upper bits zero
// Someday we will generically support data types on every math node
// Until then isOpaque indicates we shouldn't constant optimize this node type
bool isOpaque() { return VN_IS(this, CvtPackString); }
bool isOpaque() const { return VN_IS(this, CvtPackString); }
};
class AstNodeTermop VL_NOT_FINAL : public AstNodeMath {
@ -2111,9 +2143,7 @@ public:
AstNode* expr1p() const { return op2p(); } // op2 = If true...
AstNode* expr2p() const { return op3p(); } // op3 = If false...
virtual string emitVerilog() override { return "%k(%l %f? %r %k: %t)"; }
virtual string emitC() override {
return "VL_COND_%nq%lq%rq%tq(%nw,%lw,%rw,%tw, %P, %li, %ri, %ti)";
}
virtual string emitC() override { return "VL_COND_%nq%lq%rq%tq(%nw, %P, %li, %ri, %ti)"; }
virtual bool cleanOut() const override { return false; } // clean if e1 & e2 clean
virtual bool cleanLhs() const override { return true; }
virtual bool cleanRhs() const override { return false; }
@ -2166,7 +2196,7 @@ public:
AstNode* fromp() const { return op1p(); }
AstNode* rhsp() const { return op2p(); }
AstNode* thsp() const { return op3p(); }
AstAttrOf* attrp() const { return VN_CAST(op4p(), AttrOf); }
AstAttrOf* attrp() const { return VN_AS(op4p(), AttrOf); }
void fromp(AstNode* nodep) { return setOp1p(nodep); }
void rhsp(AstNode* nodep) { return setOp2p(nodep); }
void thsp(AstNode* nodep) { return setOp3p(nodep); }
@ -2304,7 +2334,7 @@ public:
virtual int instrCount() const override { return INSTR_COUNT_BRANCH; }
AstNode* exprp() const { return op1p(); } // op1 = case condition <expression>
AstCaseItem* itemsp() const {
return VN_CAST(op2p(), CaseItem);
return VN_AS(op2p(), CaseItem);
} // op2 = list of case expressions
AstNode* notParallelp() const { return op3p(); } // op3 = assertion code for non-full case's
void addItemsp(AstNode* nodep) { addOp2p(nodep); }
@ -2518,10 +2548,10 @@ public:
// For basicp() we reuse the size to indicate a "fake" basic type of same size
virtual AstBasicDType* basicp() const override {
return (isFourstate()
? VN_CAST(findLogicRangeDType(VNumRange{width() - 1, 0}, width(), numeric()),
BasicDType)
: VN_CAST(findBitRangeDType(VNumRange{width() - 1, 0}, width(), numeric()),
BasicDType));
? VN_AS(findLogicRangeDType(VNumRange{width() - 1, 0}, width(), numeric()),
BasicDType)
: VN_AS(findBitRangeDType(VNumRange{width() - 1, 0}, width(), numeric()),
BasicDType));
}
virtual AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
@ -2537,7 +2567,7 @@ public:
virtual string name() const override { return m_name; }
virtual void name(const string& flag) override { m_name = flag; }
AstMemberDType* membersp() const {
return VN_CAST(op1p(), MemberDType);
return VN_AS(op1p(), MemberDType);
} // op1 = AstMember list
void addMembersp(AstNode* nodep) { addNOp1p(nodep); }
bool packed() const { return m_packed; }
@ -2580,18 +2610,18 @@ public:
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
}
virtual bool same(const AstNode* samep) const override {
const AstNodeArrayDType* asamep = static_cast<const AstNodeArrayDType*>(samep);
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
return (hi() == asamep->hi() && subDTypep() == asamep->subDTypep()
&& rangenp()->sameTree(asamep->rangenp()));
} // HashedDT doesn't recurse, so need to check children
virtual bool similarDType(AstNodeDType* samep) const override {
const AstNodeArrayDType* asamep = static_cast<const AstNodeArrayDType*>(samep);
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
return (asamep && type() == samep->type() && hi() == asamep->hi()
&& rangenp()->sameTree(asamep->rangenp())
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
}
virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
AstNodeDType* childDTypep() const { return VN_AS(op1p(), NodeDType); }
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
virtual AstNodeDType* subDTypep() const override {
return m_refDTypep ? m_refDTypep : childDTypep();
@ -2599,7 +2629,7 @@ public:
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
virtual AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
AstRange* rangep() const { return VN_CAST(op2p(), Range); } // op2 = Array(s) of variable
AstRange* rangep() const { return VN_AS(op2p(), Range); } // op2 = Array(s) of variable
void rangep(AstRange* nodep);
// METHODS
virtual AstBasicDType* basicp() const override {
@ -2673,7 +2703,7 @@ public:
virtual const char* broken() const override;
virtual int instrCount() const override { return INSTR_COUNT_CALL; }
virtual bool same(const AstNode* samep) const override {
const AstNodeCCall* asamep = static_cast<const AstNodeCCall*>(samep);
const AstNodeCCall* const asamep = static_cast<const AstNodeCCall*>(samep);
return (funcp() == asamep->funcp() && argTypes() == asamep->argTypes());
}
AstNode* exprsp() const { return op2p(); } // op2 = expressions to print
@ -2705,6 +2735,7 @@ private:
bool m_dpiContext : 1; // DPI import context
bool m_dpiOpenChild : 1; // DPI import open array child wrapper
bool m_dpiTask : 1; // DPI import task (vs. void function)
bool m_dpiTraceInit : 1; // DPI trace_init
bool m_isConstructor : 1; // Class constructor
bool m_isHideLocal : 1; // Verilog local
bool m_isHideProtected : 1; // Verilog protected
@ -2728,6 +2759,7 @@ protected:
, m_dpiContext{false}
, m_dpiOpenChild{false}
, m_dpiTask{false}
, m_dpiTraceInit{false}
, m_isConstructor{false}
, m_isHideLocal{false}
, m_isHideProtected{false}
@ -2762,7 +2794,7 @@ public:
AstNode* stmtsp() const { return op3p(); } // op3 = List of statements
void addStmtsp(AstNode* nodep) { addNOp3p(nodep); }
// op4 = scope name
AstScopeName* scopeNamep() const { return VN_CAST(op4p(), ScopeName); }
AstScopeName* scopeNamep() const { return VN_AS(op4p(), ScopeName); }
// MORE ACCESSORS
void dpiOpenParentInc() { ++m_dpiOpenParent; }
void dpiOpenParentClear() { m_dpiOpenParent = 0; }
@ -2790,6 +2822,8 @@ public:
bool dpiOpenChild() const { return m_dpiOpenChild; }
void dpiTask(bool flag) { m_dpiTask = flag; }
bool dpiTask() const { return m_dpiTask; }
void dpiTraceInit(bool flag) { m_dpiTraceInit = flag; }
bool dpiTraceInit() const { return m_dpiTraceInit; }
void isConstructor(bool flag) { m_isConstructor = flag; }
bool isConstructor() const { return m_isConstructor; }
bool isHideLocal() const { return m_isHideLocal; }
@ -2842,7 +2876,6 @@ public:
return m_taskp && m_taskp->isGateOptimizable();
}
string dotted() const { return m_dotted; } // * = Scope name or ""
string prettyDotted() const { return prettyName(dotted()); }
string inlinedDots() const { return m_inlinedDots; }
void inlinedDots(const string& flag) { m_inlinedDots = flag; }
AstNodeFTask* taskp() const { return m_taskp; } // [After Link] Pointer to variable
@ -2860,7 +2893,7 @@ public:
AstNode* pinsp() const { return op3p(); }
void addPinsp(AstNode* nodep) { addOp3p(nodep); }
// op4 = scope tracking
AstScopeName* scopeNamep() const { return VN_CAST(op4p(), ScopeName); }
AstScopeName* scopeNamep() const { return VN_AS(op4p(), ScopeName); }
void scopeNamep(AstNode* nodep) { setNOp4p(nodep); }
};
@ -2870,7 +2903,7 @@ class AstNodeModule VL_NOT_FINAL : public AstNode {
// excluding $unit package stuff
private:
string m_name; // Name of the module
string m_origName; // Name of the module, ignoring name() changes, for dot lookup
const string m_origName; // Name of the module, ignoring name() changes, for dot lookup
string m_hierName; // Hierarchical name for errors, etc.
bool m_modPublic : 1; // Module has public references
bool m_modTrace : 1; // Tracing this module
@ -2881,7 +2914,6 @@ private:
bool m_recursive : 1; // Recursive module
bool m_recursiveClone : 1; // If recursive, what module it clones, otherwise nullptr
int m_level = 0; // 1=top module, 2=cell off top module, ...
int m_typeNum = 0; // Incrementing implicit type number
VLifetime m_lifetime; // Lifetime
VTimescale m_timeunit; // Global time unit
VOptionBool m_unconnectedDrive; // State of `unconnected_drive
@ -2906,7 +2938,7 @@ public:
virtual string name() const override { return m_name; }
virtual bool timescaleMatters() const = 0;
AstNode* stmtsp() const { return op2p(); } // op2 = List of statements
AstActive* activesp() const { return VN_CAST(op3p(), Active); } // op3 = List of i/sblocks
AstActive* activesp() const { return VN_AS(op3p(), Active); } // op3 = List of i/sblocks
// METHODS
void addInlinesp(AstNode* nodep) { addOp1p(nodep); }
void addStmtp(AstNode* nodep) { addNOp2p(nodep); }
@ -2921,7 +2953,6 @@ public:
void level(int level) { m_level = level; }
int level() const { return m_level; }
bool isTop() const { return level() == 1; }
int typeNumGetInc() { return ++m_typeNum; }
void modPublic(bool flag) { m_modPublic = flag; }
bool modPublic() const { return m_modPublic; }
void modTrace(bool flag) { m_modTrace = flag; }

View File

@ -34,7 +34,7 @@ inline int AstNode::widthInstrs() const {
return (!dtypep() ? 1 : (dtypep()->isWide() ? dtypep()->widthWords() : 1));
}
inline bool AstNode::isDouble() const {
return dtypep() && VN_IS(dtypep(), BasicDType) && VN_CAST(dtypep(), BasicDType)->isDouble();
return dtypep() && VN_IS(dtypep(), BasicDType) && VN_AS(dtypep(), BasicDType)->isDouble();
}
inline bool AstNode::isString() const {
return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString();
@ -42,19 +42,19 @@ inline bool AstNode::isString() const {
inline bool AstNode::isSigned() const { return dtypep() && dtypep()->isSigned(); }
inline bool AstNode::isZero() const {
return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isEqZero());
return (VN_IS(this, Const) && VN_AS(this, Const)->num().isEqZero());
}
inline bool AstNode::isNeqZero() const {
return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isNeqZero());
return (VN_IS(this, Const) && VN_AS(this, Const)->num().isNeqZero());
}
inline bool AstNode::isOne() const {
return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isEqOne());
return (VN_IS(this, Const) && VN_AS(this, Const)->num().isEqOne());
}
inline bool AstNode::isAllOnes() const {
return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->isEqAllOnes());
return (VN_IS(this, Const) && VN_AS(this, Const)->isEqAllOnes());
}
inline bool AstNode::isAllOnesV() const {
return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->isEqAllOnesV());
return (VN_IS(this, Const) && VN_AS(this, Const)->isEqAllOnesV());
}
inline bool AstNode::sameTree(const AstNode* node2p) const {
return sameTreeIter(this, node2p, true, false);

View File

@ -44,7 +44,7 @@ const char* AstIfaceRefDType::broken() const {
}
AstIface* AstIfaceRefDType::ifaceViaCellp() const {
return ((m_cellp && m_cellp->modp()) ? VN_CAST(m_cellp->modp(), Iface) : m_ifacep);
return ((m_cellp && m_cellp->modp()) ? VN_AS(m_cellp->modp(), Iface) : m_ifacep);
}
const char* AstNodeVarRef::broken() const {
@ -73,13 +73,13 @@ const char* AstAddrOfCFunc::broken() const {
}
int AstNodeSel::bitConst() const {
AstConst* constp = VN_CAST(bitp(), Const);
const AstConst* const constp = VN_AS(bitp(), Const);
return (constp ? constp->toSInt() : 0);
}
void AstNodeUOrStructDType::repairMemberCache() {
clearCache();
for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_CAST(itemp->nextp(), MemberDType)) {
for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) {
if (m_members.find(itemp->name()) != m_members.end()) {
itemp->v3error("Duplicate declaration of member name: " << itemp->prettyNameQ());
} else {
@ -90,7 +90,7 @@ void AstNodeUOrStructDType::repairMemberCache() {
const char* AstNodeUOrStructDType::broken() const {
std::unordered_set<AstMemberDType*> exists;
for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_CAST(itemp->nextp(), MemberDType)) {
for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) {
exists.insert(itemp);
}
for (MemberNameMap::const_iterator it = m_members.begin(); it != m_members.end(); ++it) {
@ -197,30 +197,6 @@ AstNodeBiop* AstEq::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
}
}
AstNodeBiop* AstGte::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
if (lhsp->isString() && rhsp->isString()) {
return new AstGteN(fl, lhsp, rhsp);
} else if (lhsp->isDouble() && rhsp->isDouble()) {
return new AstGteD(fl, lhsp, rhsp);
} else if (lhsp->isSigned() && rhsp->isSigned()) {
return new AstGteS(fl, lhsp, rhsp);
} else {
return new AstGte(fl, lhsp, rhsp);
}
}
AstNodeBiop* AstLte::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
if (lhsp->isString() && rhsp->isString()) {
return new AstLteN(fl, lhsp, rhsp);
} else if (lhsp->isDouble() && rhsp->isDouble()) {
return new AstLteD(fl, lhsp, rhsp);
} else if (lhsp->isSigned() && rhsp->isSigned()) {
return new AstLteS(fl, lhsp, rhsp);
} else {
return new AstLte(fl, lhsp, rhsp);
}
}
AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
if (lhsp->isString() && rhsp->isString()) {
return new AstEqN(fl, lhsp, rhsp);
@ -238,11 +214,11 @@ AstExecGraph::AstExecGraph(FileLine* fileline)
AstExecGraph::~AstExecGraph() { VL_DO_DANGLING(delete m_depGraphp, m_depGraphp); }
AstNode* AstInsideRange::newAndFromInside(AstNode* exprp, AstNode* lhsp, AstNode* rhsp) {
AstNode* ap = new AstGte(fileline(), exprp->cloneTree(true), lhsp);
AstNode* bp = new AstLte(fileline(), exprp->cloneTree(true), rhsp);
AstNode* const ap = new AstGte(fileline(), exprp->cloneTree(true), lhsp);
AstNode* const bp = new AstLte(fileline(), exprp->cloneTree(true), rhsp);
ap->fileline()->modifyWarnOff(V3ErrorCode::UNSIGNED, true);
bp->fileline()->modifyWarnOff(V3ErrorCode::CMPCONST, true);
AstNode* newp = new AstAnd(fileline(), ap, bp);
AstNode* const newp = new AstAnd(fileline(), ap, bp);
return newp;
}
@ -250,11 +226,11 @@ AstConst* AstConst::parseParamLiteral(FileLine* fl, const string& literal) {
bool success = false;
if (literal[0] == '"') {
// This is a string
string v = literal.substr(1, literal.find('"', 1) - 1);
const string v = literal.substr(1, literal.find('"', 1) - 1);
return new AstConst(fl, AstConst::VerilogStringLiteral(), v);
} else if (literal.find_first_of(".eEpP") != string::npos) {
// This may be a real
double v = VString::parseDouble(literal, &success);
const double v = VString::parseDouble(literal, &success);
if (success) return new AstConst(fl, AstConst::RealDouble(), v);
}
if (!success) {
@ -266,7 +242,7 @@ AstConst* AstConst::parseParamLiteral(FileLine* fl, const string& literal) {
// the string after the number, this is invalid C and we try
// the Verilog literal parser.
char* endp;
int v = strtol(literal.c_str(), &endp, 0);
const int v = strtol(literal.c_str(), &endp, 0);
if ((v != 0) && (endp[0] == 0)) { // C literal
return new AstConst(fl, AstConst::Signed32(), v);
} else { // Try a Verilog literal (fatals if not)
@ -360,7 +336,7 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string&
string AstVar::vlEnumType() const {
string arg;
AstBasicDType* bdtypep = basicp();
const AstBasicDType* const bdtypep = basicp();
const bool strtype = bdtypep && bdtypep->keyword() == AstBasicDTypeKwd::STRING;
if (bdtypep && bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) {
return "VLVT_PTR";
@ -401,7 +377,7 @@ string AstVar::vlEnumDir() const {
out += "|VLVF_PUB_RD";
}
//
if (AstBasicDType* bdtypep = basicp()) {
if (const AstBasicDType* const bdtypep = basicp()) {
if (bdtypep->keyword().isDpiCLayout()) out += "|VLVF_DPI_CLAY";
}
return out;
@ -413,7 +389,7 @@ string AstVar::vlPropDecl(const string& propName) const {
std::vector<int> ulims; // Unpacked dimension limits
for (const AstNodeDType* dtp = dtypep(); dtp;) {
dtp = dtp->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
if (const AstNodeArrayDType* const adtypep = VN_CAST_CONST(dtp, NodeArrayDType)) {
if (const AstNodeArrayDType* const adtypep = VN_CAST(dtp, NodeArrayDType)) {
ulims.push_back(adtypep->declRange().left());
ulims.push_back(adtypep->declRange().right());
dtp = adtypep->subDTypep();
@ -499,7 +475,7 @@ public:
string convert(const AstVar* varp) const {
if (varp->isDpiOpenArray()) {
return openArray(varp);
} else if (const AstBasicDType* basicp = varp->basicp()) {
} else if (const AstBasicDType* const basicp = varp->basicp()) {
if (basicp->isDpiBitVec() || basicp->isDpiLogicVec()) {
return bitLogicVector(varp, basicp->isDpiBitVec());
} else {
@ -539,9 +515,9 @@ string AstVar::dpiArgType(bool named, bool forReturn) const {
string AstVar::dpiTmpVarType(const string& varName) const {
class converter final : public dpiTypesToStringConverter {
string m_name;
const string m_name;
string arraySuffix(const AstVar* varp, size_t n) const {
if (AstUnpackArrayDType* unpackp
if (AstUnpackArrayDType* const unpackp
= VN_CAST(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
// Convert multi dimensional unpacked array to 1D array
if (n == 0) n = 1;
@ -607,15 +583,15 @@ AstVar* AstVar::scVarRecurse(AstNode* nodep) {
// See if this is a SC assignment; if so return that type
// Historically sc variables are identified by a variable
// attribute. TODO it would better be a data type attribute.
if (AstVar* anodep = VN_CAST(nodep, Var)) {
if (AstVar* const anodep = VN_CAST(nodep, Var)) {
if (anodep->isSc()) {
return anodep;
} else {
return nullptr;
}
} else if (VN_IS(nodep, VarRef)) {
if (VN_CAST(nodep, VarRef)->varp()->isSc()) {
return VN_CAST(nodep, VarRef)->varp();
if (VN_AS(nodep, VarRef)->varp()->isSc()) {
return VN_AS(nodep, VarRef)->varp();
} else {
return nullptr;
}
@ -666,29 +642,29 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
// Legacy compound argument currently just passed through and unused
CTypeRecursed info;
const AstNodeDType* dtypep = this->skipRefp();
if (const auto* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) {
const AstNodeDType* const dtypep = this->skipRefp();
if (const auto* const adtypep = VN_CAST(dtypep, AssocArrayDType)) {
const CTypeRecursed key = adtypep->keyDTypep()->cTypeRecurse(true);
const CTypeRecursed val = adtypep->subDTypep()->cTypeRecurse(true);
info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">";
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) {
} else if (const auto* const adtypep = VN_CAST(dtypep, DynArrayDType)) {
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
info.m_type = "VlQueue<" + sub.m_type + ">";
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, QueueDType)) {
} else if (const auto* const adtypep = VN_CAST(dtypep, QueueDType)) {
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
info.m_type = "VlQueue<" + sub.m_type;
// + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1
if (adtypep->boundp()) info.m_type += ", " + cvtToStr(adtypep->boundConst() + 1);
info.m_type += ">";
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) {
} else if (const auto* const adtypep = VN_CAST(dtypep, ClassRefDType)) {
info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
} else if (const auto* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) {
} else if (const auto* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
if (adtypep->isCompound()) compound = true;
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(compound);
info.m_type = "VlUnpacked<" + sub.m_type;
info.m_type += ", " + cvtToStr(adtypep->declRange().elements());
info.m_type += ">";
} else if (const AstBasicDType* bdtypep = dtypep->basicp()) {
} else if (const AstBasicDType* const bdtypep = dtypep->basicp()) {
// We don't print msb()/lsb() as multidim packed would require recursion,
// and may confuse users as C++ data is stored always with bit 0 used
const string bitvec = (!bdtypep->isOpaque() && !v3Global.opt.protectIds())
@ -728,7 +704,7 @@ uint32_t AstNodeDType::arrayUnpackedElements() {
uint32_t entries = 1;
for (AstNodeDType* dtypep = this; dtypep;) {
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
if (AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
entries *= adtypep->elementsConst();
dtypep = adtypep->subDTypep();
} else {
@ -745,7 +721,7 @@ std::pair<uint32_t, uint32_t> AstNodeDType::dimensions(bool includeBasic) {
uint32_t unpacked = 0;
for (AstNodeDType* dtypep = this; dtypep;) {
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
if (const AstNodeArrayDType* adtypep = VN_CAST(dtypep, NodeArrayDType)) {
if (const AstNodeArrayDType* const adtypep = VN_CAST(dtypep, NodeArrayDType)) {
if (VN_IS(adtypep, PackArrayDType)) {
++packed;
} else {
@ -753,11 +729,11 @@ std::pair<uint32_t, uint32_t> AstNodeDType::dimensions(bool includeBasic) {
}
dtypep = adtypep->subDTypep();
continue;
} else if (const AstQueueDType* qdtypep = VN_CAST(dtypep, QueueDType)) {
} else if (const AstQueueDType* const qdtypep = VN_CAST(dtypep, QueueDType)) {
unpacked++;
dtypep = qdtypep->subDTypep();
continue;
} else if (const AstBasicDType* adtypep = VN_CAST(dtypep, BasicDType)) {
} else if (const AstBasicDType* const adtypep = VN_CAST(dtypep, BasicDType)) {
if (includeBasic && (adtypep->isRanged() || adtypep->isString())) packed++;
} else if (VN_IS(dtypep, StructDType)) {
packed++;
@ -769,7 +745,7 @@ std::pair<uint32_t, uint32_t> AstNodeDType::dimensions(bool includeBasic) {
int AstNodeDType::widthPow2() const {
// I.e. width 30 returns 32, width 32 returns 32.
uint32_t width = this->width();
const uint32_t width = this->width();
for (int p2 = 30; p2 >= 0; p2--) {
if (width > (1UL << p2)) return (1UL << (p2 + 1));
}
@ -777,11 +753,11 @@ int AstNodeDType::widthPow2() const {
}
bool AstNodeDType::isLiteralType() const {
if (auto* const dtypep = VN_CAST_CONST(skipRefp(), BasicDType)) {
if (const auto* const dtypep = VN_CAST(skipRefp(), BasicDType)) {
return dtypep->keyword().isLiteralType();
} else if (auto* const dtypep = VN_CAST_CONST(skipRefp(), UnpackArrayDType)) {
} else if (const auto* const dtypep = VN_CAST(skipRefp(), UnpackArrayDType)) {
return dtypep->basicp()->isLiteralType();
} else if (auto* const dtypep = VN_CAST_CONST(skipRefp(), StructDType)) {
} else if (const auto* const dtypep = VN_CAST(skipRefp(), StructDType)) {
// Currently all structs are packed, later this can be expanded to
// 'forall members _.isLiteralType()'
return dtypep->packed();
@ -795,25 +771,25 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep, bool overMembers) {
// Else AstArraySel etc; search for the base
while (nodep) {
if (VN_IS(nodep, ArraySel)) {
nodep = VN_CAST(nodep, ArraySel)->fromp();
nodep = VN_AS(nodep, ArraySel)->fromp();
continue;
} else if (VN_IS(nodep, Sel)) {
nodep = VN_CAST(nodep, Sel)->fromp();
nodep = VN_AS(nodep, Sel)->fromp();
continue;
} else if (overMembers && VN_IS(nodep, MemberSel)) {
nodep = VN_CAST(nodep, MemberSel)->fromp();
nodep = VN_AS(nodep, MemberSel)->fromp();
continue;
}
// AstNodeSelPre stashes the associated variable under an ATTROF
// of AstAttrType::VAR_BASE/MEMBER_BASE so it isn't constified
else if (VN_IS(nodep, AttrOf)) {
nodep = VN_CAST(nodep, AttrOf)->fromp();
nodep = VN_AS(nodep, AttrOf)->fromp();
continue;
} else if (VN_IS(nodep, NodePreSel)) {
if (VN_CAST(nodep, NodePreSel)->attrp()) {
nodep = VN_CAST(nodep, NodePreSel)->attrp();
if (VN_AS(nodep, NodePreSel)->attrp()) {
nodep = VN_AS(nodep, NodePreSel)->attrp();
} else {
nodep = VN_CAST(nodep, NodePreSel)->fromp();
nodep = VN_AS(nodep, NodePreSel)->fromp();
}
continue;
} else {
@ -854,7 +830,7 @@ string AstScope::nameDotless() const {
string AstScopeName::scopePrettyNameFormatter(AstText* scopeTextp) const {
string out;
for (AstText* textp = scopeTextp; textp; textp = VN_CAST(textp->nextp(), Text)) {
for (AstText* textp = scopeTextp; textp; textp = VN_AS(textp->nextp(), Text)) {
out += textp->text();
}
// TOP will be replaced by top->name()
@ -865,7 +841,7 @@ string AstScopeName::scopePrettyNameFormatter(AstText* scopeTextp) const {
}
string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const {
string out;
for (AstText* textp = scopeTextp; textp; textp = VN_CAST(textp->nextp(), Text)) {
for (AstText* textp = scopeTextp; textp; textp = VN_AS(textp->nextp(), Text)) {
out += textp->text();
}
if (out.substr(0, 10) == "__DOT__TOP") out.replace(0, 10, "");
@ -879,28 +855,28 @@ string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const {
bool AstSenTree::hasClocked() const {
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(senp->nextp(), SenItem)) {
if (senp->isClocked()) return true;
}
return false;
}
bool AstSenTree::hasSettle() const {
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(senp->nextp(), SenItem)) {
if (senp->isSettle()) return true;
}
return false;
}
bool AstSenTree::hasInitial() const {
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(senp->nextp(), SenItem)) {
if (senp->isInitial()) return true;
}
return false;
}
bool AstSenTree::hasCombo() const {
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
for (AstSenItem* senp = sensesp(); senp; senp = VN_AS(senp->nextp(), SenItem)) {
if (senp->isCombo()) return true;
}
return false;
@ -918,7 +894,7 @@ void AstTypeTable::clearCache() {
m_detailedMap.clear();
// Clear generic()'s so dead detection will work
for (AstNode* nodep = typesp(); nodep; nodep = nodep->nextp()) {
if (AstBasicDType* bdtypep = VN_CAST(nodep, BasicDType)) bdtypep->generic(false);
if (AstBasicDType* const bdtypep = VN_CAST(nodep, BasicDType)) bdtypep->generic(false);
}
}
@ -926,7 +902,7 @@ void AstTypeTable::repairCache() {
// After we mass-change widthMin in V3WidthCommit, we need to correct the table.
clearCache();
for (AstNode* nodep = typesp(); nodep; nodep = nodep->nextp()) {
if (AstBasicDType* bdtypep = VN_CAST(nodep, BasicDType)) {
if (AstBasicDType* const bdtypep = VN_CAST(nodep, BasicDType)) {
(void)findInsertSameDType(bdtypep);
}
}
@ -934,7 +910,7 @@ void AstTypeTable::repairCache() {
AstEmptyQueueDType* AstTypeTable::findEmptyQueueDType(FileLine* fl) {
if (VL_UNLIKELY(!m_emptyQueuep)) {
AstEmptyQueueDType* newp = new AstEmptyQueueDType{fl};
AstEmptyQueueDType* const newp = new AstEmptyQueueDType{fl};
addTypesp(newp);
m_emptyQueuep = newp;
}
@ -943,7 +919,7 @@ AstEmptyQueueDType* AstTypeTable::findEmptyQueueDType(FileLine* fl) {
AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) {
if (VL_UNLIKELY(!m_voidp)) {
AstVoidDType* newp = new AstVoidDType{fl};
AstVoidDType* const newp = new AstVoidDType{fl};
addTypesp(newp);
m_voidp = newp;
}
@ -952,7 +928,7 @@ AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) {
AstQueueDType* AstTypeTable::findQueueIndexDType(FileLine* fl) {
if (VL_UNLIKELY(!m_queueIndexp)) {
AstQueueDType* newp = new AstQueueDType(fl, AstNode::findUInt32DType(), nullptr);
AstQueueDType* const newp = new AstQueueDType(fl, AstNode::findUInt32DType(), nullptr);
addTypesp(newp);
m_queueIndexp = newp;
}
@ -962,11 +938,11 @@ AstQueueDType* AstTypeTable::findQueueIndexDType(FileLine* fl) {
AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd) {
if (m_basicps[kwd]) return m_basicps[kwd];
//
AstBasicDType* new1p = new AstBasicDType(fl, kwd);
AstBasicDType* const new1p = new AstBasicDType(fl, kwd);
// Because the detailed map doesn't update this map,
// check the detailed map for this same node
// Also adds this new node to the detailed map
AstBasicDType* newp = findInsertSameDType(new1p);
AstBasicDType* const newp = findInsertSameDType(new1p);
if (newp != new1p) {
VL_DO_DANGLING(new1p->deleteTree(), new1p);
} else {
@ -979,8 +955,8 @@ AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd)
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd, int width,
int widthMin, VSigning numeric) {
AstBasicDType* new1p = new AstBasicDType(fl, kwd, numeric, width, widthMin);
AstBasicDType* newp = findInsertSameDType(new1p);
AstBasicDType* const new1p = new AstBasicDType(fl, kwd, numeric, width, widthMin);
AstBasicDType* const newp = findInsertSameDType(new1p);
if (newp != new1p) {
VL_DO_DANGLING(new1p->deleteTree(), new1p);
} else {
@ -992,8 +968,8 @@ AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kw
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd,
const VNumRange& range, int widthMin,
VSigning numeric) {
AstBasicDType* new1p = new AstBasicDType(fl, kwd, numeric, range, widthMin);
AstBasicDType* newp = findInsertSameDType(new1p);
AstBasicDType* const new1p = new AstBasicDType(fl, kwd, numeric, range, widthMin);
AstBasicDType* const newp = findInsertSameDType(new1p);
if (newp != new1p) {
VL_DO_DANGLING(new1p->deleteTree(), new1p);
} else {
@ -1003,8 +979,8 @@ AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kw
}
AstBasicDType* AstTypeTable::findInsertSameDType(AstBasicDType* nodep) {
VBasicTypeKey key(nodep->width(), nodep->widthMin(), nodep->numeric(), nodep->keyword(),
nodep->nrange());
const VBasicTypeKey key(nodep->width(), nodep->widthMin(), nodep->numeric(), nodep->keyword(),
nodep->nrange());
DetailedMap& mapr = m_detailedMap;
const auto it = mapr.find(key);
if (it != mapr.end()) return it->second;
@ -1041,10 +1017,8 @@ static bool sameInit(const AstInitArray* ap, const AstInitArray* bp) {
// - the default/inititem children might be in different order yet still yield the same table
// See note in AstInitArray::same about the same. This function instead compares by initializer
// value, rather than by tree structure.
const AstUnpackArrayDType* const aDTypep = VN_CAST(ap->dtypep(), UnpackArrayDType);
const AstUnpackArrayDType* const bDTypep = VN_CAST(bp->dtypep(), UnpackArrayDType);
UASSERT_STATIC(aDTypep, "Bad type in array initializer");
UASSERT_STATIC(bDTypep, "Bad type in array initializer");
const AstUnpackArrayDType* const aDTypep = VN_AS(ap->dtypep(), UnpackArrayDType);
const AstUnpackArrayDType* const bDTypep = VN_AS(bp->dtypep(), UnpackArrayDType);
if (!aDTypep->subDTypep()->sameTree(bDTypep->subDTypep())) { // Element types differ
return false;
}
@ -1063,14 +1037,14 @@ static bool sameInit(const AstInitArray* ap, const AstInitArray* bp) {
}
AstVarScope* AstConstPool::findTable(AstInitArray* initp) {
AstNode* const defaultp = initp->defaultp();
const AstNode* const defaultp = initp->defaultp();
// Verify initializer is well formed
UASSERT_OBJ(VN_IS(initp->dtypep(), UnpackArrayDType), initp,
"Const pool table must have AstUnpackArrayDType dtype");
UASSERT_OBJ(!defaultp || VN_IS(defaultp, Const), initp,
"Const pool table default must be Const");
for (AstNode* nodep = initp->initsp(); nodep; nodep = nodep->nextp()) {
AstNode* const valuep = VN_CAST(nodep, InitItem)->valuep();
const AstNode* const valuep = VN_AS(nodep, InitItem)->valuep();
UASSERT_OBJ(VN_IS(valuep, Const), valuep, "Const pool table entry must be Const");
}
// Try to find an existing table with the same content
@ -1078,7 +1052,7 @@ AstVarScope* AstConstPool::findTable(AstInitArray* initp) {
const auto& er = m_tables.equal_range(hash.value());
for (auto it = er.first; it != er.second; ++it) {
AstVarScope* const varScopep = it->second;
const AstInitArray* const init2p = VN_CAST(varScopep->varp()->valuep(), InitArray);
const AstInitArray* const init2p = VN_AS(varScopep->varp()->valuep(), InitArray);
if (sameInit(initp, init2p)) {
return varScopep; // Found identical table
}
@ -1107,7 +1081,7 @@ AstVarScope* AstConstPool::findConst(AstConst* initp, bool mergeDType) {
const auto& er = m_consts.equal_range(hash.value());
for (auto it = er.first; it != er.second; ++it) {
AstVarScope* const varScopep = it->second;
const AstConst* const init2p = VN_CAST(varScopep->varp()->valuep(), Const);
const AstConst* const init2p = VN_AS(varScopep->varp()->valuep(), Const);
if (sameInit(initp, init2p)
&& (mergeDType || varScopep->dtypep()->sameTree(initp->dtypep()))) {
return varScopep; // Found identical constant
@ -1218,7 +1192,7 @@ void AstNode::dump(std::ostream& str) const {
} else {
str << " @dt=" << nodeAddr(dtypep()) << "@";
}
if (AstNodeDType* dtp = dtypep()) dtp->dumpSmall(str);
if (AstNodeDType* const dtp = dtypep()) dtp->dumpSmall(str);
} else { // V3Broken will throw an error
if (dtypep()) str << " %Error-dtype-exp=null,got=" << nodeAddr(dtypep());
}
@ -1284,9 +1258,8 @@ const char* AstClassPackage::broken() const {
return nullptr;
}
void AstClass::insertCache(AstNode* nodep) {
const bool doit
= (VN_IS(nodep, Var) || VN_IS(nodep, EnumItemRef)
|| (VN_IS(nodep, NodeFTask) && !VN_CAST(nodep, NodeFTask)->isExternProto()));
const bool doit = (VN_IS(nodep, Var) || VN_IS(nodep, EnumItemRef)
|| (VN_IS(nodep, NodeFTask) && !VN_AS(nodep, NodeFTask)->isExternProto()));
if (doit) {
if (m_members.find(nodep->name()) != m_members.end()) {
nodep->v3error("Duplicate declaration of member name: " << nodep->prettyNameQ());
@ -1312,9 +1285,9 @@ void AstClass::dump(std::ostream& str) const {
if (isVirtual()) str << " [VIRT]";
}
AstClass* AstClassExtends::classp() const {
AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType);
const AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType);
if (VL_UNLIKELY(!refp)) { // LinkDot uses this for 'super.'
refp = VN_CAST(childDTypep(), ClassRefDType);
refp = VN_AS(childDTypep(), ClassRefDType);
}
UASSERT_OBJ(refp, this, "class extends non-ref");
return refp->classp();
@ -1501,7 +1474,7 @@ void AstNodeUOrStructDType::dump(std::ostream& str) const {
void AstNodeDType::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (generic()) str << " [GENERIC]";
if (AstNodeDType* dtp = virtRefDTypep()) {
if (AstNodeDType* const dtp = virtRefDTypep()) {
str << " refdt=" << nodeAddr(dtp);
dtp->dumpSmall(str);
}
@ -1515,7 +1488,7 @@ void AstNodeDType::dumpSmall(std::ostream& str) const {
}
void AstNodeArrayDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
if (auto* adtypep = VN_CAST_CONST(this, UnpackArrayDType)) {
if (auto* const adtypep = VN_CAST(this, UnpackArrayDType)) {
// uc = packed compound object, u = unpacked POD
str << (adtypep->isCompound() ? "uc" : "u");
} else {
@ -1551,7 +1524,7 @@ std::vector<AstUnpackArrayDType*> AstUnpackArrayDType::unpackDimensions() {
std::vector<AstUnpackArrayDType*> dims;
for (AstUnpackArrayDType* unpackp = this; unpackp;) {
dims.push_back(unpackp);
if (AstNodeDType* subp = unpackp->subDTypep()) {
if (AstNodeDType* const subp = unpackp->subDTypep()) {
unpackp = VN_CAST(subp, UnpackArrayDType);
} else {
unpackp = nullptr;
@ -1608,7 +1581,7 @@ void AstMTaskBody::dump(std::ostream& str) const {
void AstTypeTable::dump(std::ostream& str) const {
this->AstNode::dump(str);
for (int i = 0; i < static_cast<int>(AstBasicDTypeKwd::_ENUM_MAX); ++i) {
if (AstBasicDType* subnodep = m_basicps[i]) {
if (AstBasicDType* const subnodep = m_basicps[i]) {
str << '\n'; // Newline from caller, so newline first
str << "\t\t" << std::setw(8) << AstBasicDTypeKwd(i).ascii();
str << " -> ";
@ -1618,7 +1591,7 @@ void AstTypeTable::dump(std::ostream& str) const {
{
const DetailedMap& mapr = m_detailedMap;
for (const auto& itr : mapr) {
AstBasicDType* dtypep = itr.second;
AstBasicDType* const dtypep = itr.second;
str << '\n'; // Newline from caller, so newline first
str << "\t\tdetailed -> ";
dtypep->dump(str);
@ -1727,6 +1700,11 @@ void AstScope::dump(std::ostream& str) const {
str << " [cellp=" << reinterpret_cast<const void*>(aboveCellp()) << "]";
str << " [modp=" << reinterpret_cast<const void*>(modp()) << "]";
}
void AstScopeName::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (dpiExport()) str << " [DPIEX]";
if (forFormat()) str << " [FMT]";
}
void AstSenTree::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isMulti()) str << " [MULTI]";

File diff suppressed because it is too large Load Diff

View File

@ -103,7 +103,7 @@ public:
// Get a reference to the user data
T_Data& operator()(const T_Node* nodep) {
T_Data* userp = getUserp(nodep);
T_Data* const userp = getUserp(nodep);
UASSERT_OBJ(userp, nodep, "Missing User data on const AstNode");
return *userp;
}

View File

@ -41,7 +41,7 @@ private:
// NODE STATE
// Entire netlist:
// AstNodeFTask::user1 -> bool, 1=processed
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
bool m_anyFuncInBegin = false;
public:
@ -59,10 +59,11 @@ public:
class BeginVisitor final : public AstNVisitor {
private:
// STATE
BeginState* m_statep; // Current global state
BeginState* const m_statep; // Current global state
AstNodeModule* m_modp = nullptr; // Current module
AstNodeFTask* m_ftaskp = nullptr; // Current function/task
const AstNodeFTask* m_ftaskp = nullptr; // Current function/task
AstNode* m_liftedp = nullptr; // Local nodes we are lifting into m_ftaskp
string m_displayScope; // Name of %m in $display/AstScopeName
string m_namedScope; // Name of begin blocks above us
string m_unnamedScope; // Name of begin blocks, including unnamed blocks
int m_ifDepth = 0; // Current if depth
@ -111,9 +112,11 @@ private:
// naming; so that any begin's inside the function will rename
// inside the function.
// Process children
VL_RESTORER(m_displayScope);
VL_RESTORER(m_namedScope);
VL_RESTORER(m_unnamedScope);
{
m_displayScope = dot(m_displayScope, nodep->name());
m_namedScope = "";
m_unnamedScope = "";
m_ftaskp = nodep;
@ -134,6 +137,7 @@ private:
virtual 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);
VL_RESTORER(m_namedScope);
VL_RESTORER(m_unnamedScope);
{
@ -145,11 +149,14 @@ private:
while ((pos = dottedname.find("__DOT__")) != string::npos) {
const string ident = dottedname.substr(0, pos);
dottedname = dottedname.substr(pos + strlen("__DOT__"));
if (nodep->name() != "") m_namedScope = dot(m_namedScope, ident);
if (nodep->name() != "") {
m_displayScope = dot(m_displayScope, ident);
m_namedScope = dot(m_namedScope, ident);
}
m_unnamedScope = dot(m_unnamedScope, ident);
// Create CellInline for dotted var resolution
if (!m_ftaskp) {
AstCellInline* inlinep = new AstCellInline(
AstCellInline* const inlinep = new AstCellInline(
nodep->fileline(), m_unnamedScope, "__BEGIN__", m_modp->timeunit());
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
}
@ -162,7 +169,7 @@ private:
// Cleanup
AstNode* addsp = nullptr;
if (AstNode* stmtsp = nodep->stmtsp()) {
if (AstNode* const stmtsp = nodep->stmtsp()) {
stmtsp->unlinkFrBackWithNext();
if (addsp) {
addsp = addsp->addNextNull(stmtsp);
@ -220,11 +227,13 @@ private:
// 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
if (m_namedScope != "") {
// DPI svGetScope doesn't include function name, but %m does
const string scname = nodep->forFormat() ? m_displayScope : m_namedScope;
if (!scname.empty()) {
// To keep correct visual order, must add before other Text's
AstNode* afterp = nodep->scopeAttrp();
AstNode* const afterp = nodep->scopeAttrp();
if (afterp) afterp->unlinkFrBackWithNext();
nodep->scopeAttrp(new AstText(nodep->fileline(), string("__DOT__") + m_namedScope));
nodep->scopeAttrp(new AstText{nodep->fileline(), string("__DOT__") + scname});
if (afterp) nodep->scopeAttrp(afterp);
}
iterateChildren(nodep);
@ -308,8 +317,8 @@ void V3Begin::debeginAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{
BeginState state;
{ BeginVisitor bvisitor{nodep, &state}; }
if (state.anyFuncInBegin()) { BeginRelinkVisitor brvisitor(nodep, &state); }
{ BeginVisitor{nodep, &state}; }
if (state.anyFuncInBegin()) { BeginRelinkVisitor{nodep, &state}; }
} // Destruct before checking
V3Global::dumpCheckGlobalTree("begin", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -40,7 +40,7 @@ private:
// NODE STATE
// Entire netlist:
// AstFTask::user1() -> int. Number of references
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// STATE
int m_likely = false; // Excuses for branch likely taken
@ -123,5 +123,5 @@ public:
void V3Branch::branchAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
BranchVisitor visitor{nodep};
{ BranchVisitor{nodep}; }
}

View File

@ -191,13 +191,13 @@ private:
void processEnter(AstNode* nodep) {
nodep->brokenState(m_brokenCntCurrentUnder);
const char* whyp = nodep->broken();
const char* const whyp = nodep->broken();
UASSERT_OBJ(!whyp, nodep,
"Broken link in node (or something without maybePointedTo): " << whyp);
if (nodep->dtypep()) {
UASSERT_OBJ(nodep->dtypep()->brokeExists(), nodep,
"Broken link in node->dtypep() to " << cvtToHex(nodep->dtypep()));
UASSERT_OBJ(VN_IS(nodep->dtypep(), NodeDType), nodep,
UASSERT_OBJ(nodep->dtypep(), nodep,
"Non-dtype link in node->dtypep() to " << cvtToHex(nodep->dtypep()));
}
if (v3Global.assertDTypesResolved()) {
@ -210,7 +210,8 @@ private:
}
UASSERT_OBJ(!nodep->getChildDTypep(), nodep,
"childDTypep() non-null on node after should have removed");
if (const AstNodeDType* dnodep = VN_CAST(nodep, NodeDType)) checkWidthMin(dnodep);
if (const AstNodeDType* const dnodep = VN_CAST(nodep, NodeDType))
checkWidthMin(dnodep);
}
checkWidthMin(nodep);
}
@ -242,7 +243,7 @@ private:
processAndIterate(nodep);
UASSERT_OBJ(!(v3Global.assertDTypesResolved() && nodep->brokeLhsMustBeLvalue()
&& VN_IS(nodep->lhsp(), NodeVarRef)
&& !VN_CAST(nodep->lhsp(), NodeVarRef)->access().isWriteOrRW()),
&& !VN_AS(nodep->lhsp(), NodeVarRef)->access().isWriteOrRW()),
nodep, "Assignment LHS is not an lvalue");
}
virtual void visit(AstScope* nodep) override {
@ -342,8 +343,8 @@ void V3Broken::brokenAll(AstNetlist* nodep) {
UINFO(1, "Broken called under broken, skipping recursion.\n"); // LCOV_EXCL_LINE
} else {
inBroken = true;
BrokenMarkVisitor mvisitor{nodep};
BrokenCheckVisitor cvisitor{nodep};
const BrokenMarkVisitor mvisitor{nodep};
const BrokenCheckVisitor cvisitor{nodep};
s_allocTable.checkForLeaks();
s_linkableTable.clear();
s_brokenCntGlobal.inc();

View File

@ -39,7 +39,7 @@ public:
enum en : uint8_t { MODULE, CLASS, COVERAGE };
private:
enum en m_e;
const enum en m_e;
public:
// cppcheck-suppress noExplicitConstructor
@ -139,7 +139,8 @@ void V3CCtors::evalAsserts() {
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
if (AstVar* const varp = VN_CAST(np, Var)) {
if (varp->isPrimaryInish() && !varp->isSc()) {
if (AstBasicDType* basicp = VN_CAST(varp->dtypeSkipRefp(), BasicDType)) {
if (const AstBasicDType* const basicp
= VN_CAST(varp->dtypeSkipRefp(), BasicDType)) {
const int storedWidth = basicp->widthAlignBytes() * 8;
const int lastWordWidth = varp->width() % storedWidth;
if (lastWordWidth != 0) {
@ -175,7 +176,7 @@ void V3CCtors::cctorsAll() {
UINFO(2, __FUNCTION__ << ": " << endl);
evalAsserts();
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp;
modp = VN_CAST(modp->nextp(), NodeModule)) {
modp = VN_AS(modp->nextp(), NodeModule)) {
// Process each module in turn
{
V3CCtorsBuilder var_reset{modp, "_ctor_var_reset",
@ -200,7 +201,7 @@ void V3CCtors::cctorsAll() {
}
}
}
if (AstClass* const classp = VN_CAST(modp, Class)) {
if (const AstClass* const classp = VN_CAST(modp, Class)) {
AstCFunc* const funcp = new AstCFunc{modp->fileline(), "~", nullptr, ""};
funcp->isDestructor(true);
funcp->isStatic(false);

View File

@ -39,7 +39,7 @@
class CUseVisitor final : public AstNVisitor {
// NODE STATE
// AstNode::user1() -> bool. True if already visited
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// MEMBERS
bool m_impOnly = false; // In details needed only for implementation
@ -100,7 +100,7 @@ void V3CUse::cUseAll() {
UINFO(2, __FUNCTION__ << ": " << endl);
// Call visitor separately for each module, so visitor state is cleared
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp;
modp = VN_CAST(modp->nextp(), NodeModule)) {
modp = VN_AS(modp->nextp(), NodeModule)) {
// Insert under this module; someday we should e.g. make Ast
// for each output file and put under that
CUseVisitor{modp};

View File

@ -52,20 +52,20 @@
class CaseLintVisitor final : public AstNVisitor {
private:
AstNodeCase* m_caseExprp
const AstNodeCase* m_caseExprp
= nullptr; // Under a CASE value node, if so the relevant case statement
// METHODS
VL_DEBUG_FUNC; // Declare debug()
virtual void visit(AstNodeCase* nodep) override {
if (VN_IS(nodep, Case) && VN_CAST(nodep, Case)->casex()) {
if (VN_IS(nodep, Case) && VN_AS(nodep, Case)->casex()) {
nodep->v3warn(CASEX, "Suggest casez (with ?'s) in place of casex (with X's)");
}
// Detect multiple defaults
bool hitDefault = false;
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
itemp = VN_AS(itemp->nextp(), CaseItem)) {
if (itemp->isDefault()) {
if (hitDefault) {
itemp->v3error("Multiple default statements in case statement.");
@ -79,7 +79,7 @@ private:
m_caseExprp = nodep;
iterate(nodep->exprp());
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
itemp = VN_AS(itemp->nextp(), CaseItem)) {
iterateAndNextNull(itemp->condsp());
}
m_caseExprp = nullptr;
@ -91,11 +91,11 @@ private:
if (VN_IS(m_caseExprp, GenCase)) {
nodep->v3error("Use of x/? constant in generate case statement, "
"(no such thing as 'generate casez')");
} else if (VN_IS(m_caseExprp, Case) && VN_CAST(m_caseExprp, Case)->casex()) {
} else if (VN_IS(m_caseExprp, Case) && VN_AS(m_caseExprp, Case)->casex()) {
// Don't sweat it, we already complained about casex in general
} else if (VN_IS(m_caseExprp, Case)
&& (VN_CAST(m_caseExprp, Case)->casez()
|| VN_CAST(m_caseExprp, Case)->caseInside())) {
&& (VN_AS(m_caseExprp, Case)->casez()
|| VN_AS(m_caseExprp, Case)->caseInside())) {
if (nodep->num().isAnyX()) {
nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, "
"(perhaps intended ?/z in constant)");
@ -122,12 +122,12 @@ private:
// NODE STATE
// Cleared each Case
// AstIf::user3() -> bool. Set true to indicate clone not needed
AstUser3InUse m_inuser3;
const AstUser3InUse m_inuser3;
// STATE
VDouble0 m_statCaseFast; // Statistic tracking
VDouble0 m_statCaseSlow; // Statistic tracking
AstNode* m_alwaysp = nullptr; // Always in which case is located
const AstNode* m_alwaysp = nullptr; // Always in which case is located
// Per-CASE
int m_caseWidth = 0; // Width of valueItems
@ -145,7 +145,7 @@ private:
m_caseItems = 0;
m_caseNoOverlapsAllCovered = true;
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
itemp = VN_AS(itemp->nextp(), CaseItem)) {
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondp->nextp()) {
if (icondp->width() > width) width = icondp->width();
if (icondp->isDouble()) opaque = true;
@ -159,7 +159,7 @@ private:
return false; // Too wide for analysis
}
UINFO(8, "Simple case statement: " << nodep << endl);
uint32_t numCases = 1UL << m_caseWidth;
const uint32_t numCases = 1UL << m_caseWidth;
// Zero list of items for each value
for (uint32_t i = 0; i < numCases; ++i) m_valueItem[i] = nullptr;
// Now pick up the values for each assignment
@ -167,20 +167,20 @@ private:
bool reportedOverlap = false;
bool reportedSubcase = false;
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
itemp = VN_AS(itemp->nextp(), CaseItem)) {
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondp->nextp()) {
// if (debug() >= 9) icondp->dumpTree(cout, " caseitem: ");
AstConst* iconstp = VN_CAST(icondp, Const);
AstConst* const iconstp = VN_AS(icondp, Const);
UASSERT_OBJ(iconstp, nodep, "above 'can't parse' should have caught this");
if (neverItem(nodep, iconstp)) {
// X in casez can't ever be executed
} else {
V3Number nummask(itemp, iconstp->width());
nummask.opBitsNonX(iconstp->num());
uint32_t mask = nummask.toUInt();
const uint32_t mask = nummask.toUInt();
V3Number numval(itemp, iconstp->width());
numval.opBitsOne(iconstp->num());
uint32_t val = numval.toUInt();
const uint32_t val = numval.toUInt();
uint32_t firstOverlap = 0;
bool foundOverlap = false;
@ -190,7 +190,7 @@ private:
if (!m_valueItem[i]) {
m_valueItem[i] = itemp;
foundHit = true;
} else if (!foundOverlap && !itemp->ignoreOverlap()) {
} else if (!foundOverlap) {
firstOverlap = i;
foundOverlap = true;
m_caseNoOverlapsAllCovered = false;
@ -244,7 +244,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_CAST(m_valueItem[i], CaseItem)->bodysp();
m_valueItem[i] = VN_AS(m_valueItem[i], CaseItem)->bodysp();
}
return true; // All is fine
}
@ -289,10 +289,11 @@ private:
// V3Number nummask (cexprp, cexprp->width(), (1UL<<msb));
// AstNode* and1p = new AstAnd(cexprp->fileline(), cexprp->cloneTree(false),
// new AstConst(cexprp->fileline(), nummask));
AstNode* and1p = new AstSel(cexprp->fileline(), cexprp->cloneTree(false), msb, 1);
AstNode* eqp
AstNode* const and1p
= new AstSel(cexprp->fileline(), cexprp->cloneTree(false), msb, 1);
AstNode* const eqp
= new AstNeq(cexprp->fileline(), new AstConst(cexprp->fileline(), 0), and1p);
AstIf* ifp = new AstIf(cexprp->fileline(), eqp, tree1p, tree0p);
AstIf* const ifp = new AstIf(cexprp->fileline(), eqp, tree1p, tree0p);
ifp->user3(1); // So we don't bother to clone it
return ifp;
}
@ -302,11 +303,11 @@ private:
// CASEx(cexpr,....
// -> tree of IF(msb, IF(msb-1, 11, 10)
// IF(msb-1, 01, 00))
AstNode* cexprp = nodep->exprp()->unlinkFrBack();
AstNode* const cexprp = nodep->exprp()->unlinkFrBack();
if (debug() >= 9) { // LCOV_EXCL_START
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) {
if (AstNode* itemp = m_valueItem[i]) {
if (const AstNode* const itemp = m_valueItem[i]) {
UINFO(9, "Value " << std::hex << i << " " << itemp << endl);
}
}
@ -335,13 +336,13 @@ private:
// -> IF((cexpr==icond1),istmts1,
// IF((EQ (AND MASK cexpr) (AND MASK icond1)
// ,istmts2, istmts3
AstNode* cexprp = nodep->exprp()->unlinkFrBack();
AstNode* const cexprp = nodep->exprp()->unlinkFrBack();
// We'll do this in two stages. First stage, convert the conditions to
// the appropriate IF AND terms.
if (debug() >= 9) nodep->dumpTree(cout, " _comp_IN: ");
bool hadDefault = false;
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
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()));
@ -355,7 +356,7 @@ private:
icondp->unlinkFrBack();
AstNode* condp = nullptr; // Default is to use and1p/and2p
AstConst* iconstp = VN_CAST(icondp, Const);
AstConst* const iconstp = VN_CAST(icondp, Const);
if (iconstp && neverItem(nodep, iconstp)) {
// X in casez can't ever be executed
VL_DO_DANGLING(icondp->deleteTree(), icondp);
@ -363,7 +364,7 @@ private:
// For simplicity, make expression that is not equal, and let later
// optimizations remove it
condp = new AstConst(itemp->fileline(), AstConst::BitFalse());
} else if (AstInsideRange* irangep = VN_CAST(icondp, InsideRange)) {
} else if (AstInsideRange* const irangep = VN_CAST(icondp, InsideRange)) {
// Similar logic in V3Width::visit(AstInside)
condp = irangep->newAndFromInside(cexprp, irangep->lhsp()->unlinkFrBack(),
irangep->rhsp()->unlinkFrBack());
@ -373,18 +374,19 @@ private:
nummask.opBitsNonX(iconstp->num());
V3Number numval(itemp, iconstp->width());
numval.opBitsOne(iconstp->num());
AstNode* and1p = new AstAnd(itemp->fileline(), cexprp->cloneTree(false),
new AstConst(itemp->fileline(), nummask));
AstNode* and2p = new AstAnd(itemp->fileline(),
new AstConst(itemp->fileline(), numval),
new AstConst(itemp->fileline(), nummask));
AstNode* const and1p
= new AstAnd(itemp->fileline(), cexprp->cloneTree(false),
new AstConst(itemp->fileline(), nummask));
AstNode* const and2p = new AstAnd(
itemp->fileline(), new AstConst(itemp->fileline(), numval),
new AstConst(itemp->fileline(), nummask));
VL_DO_DANGLING(icondp->deleteTree(), icondp);
VL_DANGLING(iconstp);
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
} else {
// Not a caseX mask, we can simply build CASEEQ(cexpr icond)
AstNode* and1p = cexprp->cloneTree(false);
AstNode* and2p = icondp;
AstNode* const and1p = cexprp->cloneTree(false);
AstNode* const and2p = icondp;
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
}
if (!ifexprp) {
@ -416,16 +418,16 @@ private:
AstIf* groupnextp = nullptr;
AstIf* itemnextp = nullptr;
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
AstNode* istmtsp = itemp->bodysp(); // Maybe null -- no action.
itemp = VN_AS(itemp->nextp(), CaseItem)) {
AstNode* const istmtsp = itemp->bodysp(); // Maybe null -- no action.
if (istmtsp) istmtsp->unlinkFrBackWithNext();
// Expressioned clause
AstNode* ifexprp = itemp->condsp()->unlinkFrBack();
AstNode* const ifexprp = itemp->condsp()->unlinkFrBack();
{ // Prepare for next group
if (++depth > CASE_ENCODER_GROUP_DEPTH) depth = 1;
if (depth == 1) { // First group or starting new group
itemnextp = nullptr;
AstIf* newp
AstIf* const newp
= new AstIf(itemp->fileline(), ifexprp->cloneTree(true), nullptr, nullptr);
if (groupnextp) {
groupnextp->addElsesp(newp);
@ -434,7 +436,7 @@ private:
}
groupnextp = newp;
} else { // Continue group, modify if condition to OR in this new condition
AstNode* condp = groupnextp->condp()->unlinkFrBack();
AstNode* const condp = groupnextp->condp()->unlinkFrBack();
groupnextp->condp(
new AstOr(ifexprp->fileline(), condp, ifexprp->cloneTree(true)));
}
@ -446,7 +448,7 @@ private:
VL_DO_DANGLING(itemexprp->deleteTree(), itemexprp);
itemexprp = new AstConst(itemp->fileline(), AstConst::BitTrue());
}
AstIf* newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, nullptr);
AstIf* const newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, nullptr);
if (itemnextp) {
itemnextp->addElsesp(newp);
} else {
@ -474,7 +476,7 @@ private:
// covered, we're done with it.
// Else, convert to a normal statement parallel with the case statement.
if (nodep->notParallelp() && !noOverlapsAllCovered) {
AstNode* parp = nodep->notParallelp()->unlinkFrBackWithNext();
AstNode* const parp = nodep->notParallelp()->unlinkFrBackWithNext();
nodep->addNextHere(parp);
}
}
@ -530,10 +532,10 @@ public:
void V3Case::caseAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CaseVisitor visitor{nodep}; } // Destruct before checking
{ CaseVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("case", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
void V3Case::caseLint(AstNodeCase* nodep) {
UINFO(4, __FUNCTION__ << ": " << endl);
CaseLintVisitor visitor{nodep};
{ CaseLintVisitor{nodep}; }
}

View File

@ -54,7 +54,7 @@ private:
// NODE STATE
// Entire netlist:
// AstNode::user() // bool. Indicates node is of known size
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// STATE
@ -155,7 +155,7 @@ private:
}
}
virtual void visit(AstVarRef* nodep) override {
AstNode* const backp = nodep->backp();
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()
&& castSize(nodep) != castSize(nodep->varp())) {
@ -203,6 +203,6 @@ public:
void V3Cast::castAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CastVisitor visitor{nodep}; } // Destruct before checking
{ CastVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("cast", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -50,8 +50,8 @@ public:
// Graph support classes
class CdcEitherVertex VL_NOT_FINAL : public V3GraphVertex {
AstScope* m_scopep;
AstNode* m_nodep;
AstScope* const m_scopep;
AstNode* const m_nodep;
AstSenTree* m_srcDomainp = nullptr;
AstSenTree* m_dstDomainp = nullptr;
bool m_srcDomainSet : 1;
@ -84,7 +84,7 @@ public:
};
class CdcVarVertex final : public CdcEitherVertex {
AstVarScope* m_varScp;
AstVarScope* const m_varScp;
int m_cntAsyncRst = 0;
bool m_fromFlop = false;
@ -217,15 +217,15 @@ private:
// AstVarScope::user2 -> bool Used in sensitivity list
// {statement}Node::user1p -> CdcLogicVertex* for this statement
// AstNode::user3 -> bool True indicates to print %% (via V3EmitV)
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
const AstUser1InUse m_inuser1;
const AstUser2InUse m_inuser2;
const AstUser3InUse m_inuser3;
// STATE
V3Graph m_graph; // Scoreboard of var usages/dependencies
CdcLogicVertex* m_logicVertexp = nullptr; // Current statement being tracked, nullptr=ignored
AstScope* m_scopep = nullptr; // Current scope being processed
AstNodeModule* m_modp = nullptr; // Current module
const AstNodeModule* m_modp = nullptr; // Current module
AstSenTree* m_domainp = nullptr; // Current sentree
bool m_inDly = false; // In delayed assign
int m_inSenItem = 0; // Number of senitems
@ -266,7 +266,7 @@ private:
if (varscp->varp()->isPrimaryIO()) {
// Create IO vertex - note it's relative to the pointed to var, not where we are
// now This allows reporting to easily print the input statement
CdcLogicVertex* ioVertexp
CdcLogicVertex* const ioVertexp
= new CdcLogicVertex(&m_graph, varscp->scopep(), varscp->varp(), nullptr);
if (varscp->varp()->isWritable()) {
new V3GraphEdge(&m_graph, vertexp, ioVertexp, 1);
@ -337,7 +337,7 @@ private:
int filelineWidth() {
if (!m_filelineWidth) {
CdcWidthVisitor visitor{v3Global.rootp()};
const CdcWidthVisitor visitor{v3Global.rootp()};
m_filelineWidth = visitor.maxWidth();
}
return m_filelineWidth;
@ -351,12 +351,12 @@ private:
// userClearVertices is very slow, so we use a generation count instead
m_graph.userClearVertices(); // user1: uint32_t - was analyzed generation
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
if (CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
if (vvertexp->cntAsyncRst()) {
m_userGeneration++; // Effectively a userClearVertices()
UINFO(8, " Trace One async: " << vvertexp << endl);
// Twice, as we need to detect, then propagate
CdcEitherVertex* markp = traceAsyncRecurse(vvertexp, false);
CdcEitherVertex* const markp = traceAsyncRecurse(vvertexp, false);
if (markp) { // Mark is non-nullptr if something bad on this path
UINFO(9, " Trace One bad! " << vvertexp << endl);
m_userGeneration++; // Effectively a userClearVertices()
@ -381,17 +381,18 @@ private:
// Clear out in prep for marking next path
if (!mark) vertexp->asyncPath(false);
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
if (CdcLogicVertex* const vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
// Any logic considered bad, at the moment, anyhow
if (vvertexp->hazard() && !mark_outp) mark_outp = vvertexp;
// And keep tracing back so the user can understand what's up
} else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
} else if (CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
if (mark) vvertexp->asyncPath(true);
// If primary I/O, it's ok here back
if (vvertexp->varScp()->varp()->isPrimaryInish()) {
// Show the source "input" statement if it exists
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
CdcEitherVertex* const eFromVertexp
= static_cast<CdcEitherVertex*>(edgep->fromp());
eFromVertexp->asyncPath(true);
}
return nullptr;
@ -399,7 +400,8 @@ private:
// Also ok if from flop, but partially trace the flop so more obvious to users
if (vvertexp->fromFlop()) {
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
CdcEitherVertex* const eFromVertexp
= static_cast<CdcEitherVertex*>(edgep->fromp());
eFromVertexp->asyncPath(true);
}
return nullptr;
@ -407,8 +409,8 @@ private:
}
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
CdcEitherVertex* submarkp = traceAsyncRecurse(eFromVertexp, mark);
CdcEitherVertex* const eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
CdcEitherVertex* const submarkp = traceAsyncRecurse(eFromVertexp, mark);
if (submarkp && !mark_outp) mark_outp = submarkp;
}
@ -417,14 +419,14 @@ private:
}
void dumpAsync(CdcVarVertex* vertexp, CdcEitherVertex* markp) {
AstNode* nodep = vertexp->varScp();
const AstNode* const nodep = vertexp->varScp();
*m_ofp << "\n";
*m_ofp << "\n";
CdcEitherVertex* targetp = vertexp; // One example destination flop (of possibly many)
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
CdcEitherVertex* eToVertexp = static_cast<CdcEitherVertex*>(edgep->top());
CdcEitherVertex* const eToVertexp = static_cast<CdcEitherVertex*>(edgep->top());
if (!eToVertexp) targetp = eToVertexp;
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(eToVertexp)) {
if (const CdcLogicVertex* const vvertexp = dynamic_cast<CdcLogicVertex*>(eToVertexp)) {
if (vvertexp->isFlop() // IE the target flop that is upsetting us
&& edgep->weight() >= CDC_WEIGHT_ASYNC) { // And var feeds an async reset line
targetp = eToVertexp;
@ -452,14 +454,14 @@ private:
const string cont = prefix + sep;
string nextsep = " ";
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
CdcEitherVertex* const eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
if (dumpAsyncRecurse(eFromVertexp, cont, nextsep, level + 1)) nextsep = " | ";
}
// Dump single variable/logic block
// See also OrderGraph::loopsVertexCb(V3GraphVertex* vertexp)
AstNode* nodep = vertexp->nodep();
string front
AstNode* const nodep = vertexp->nodep();
const string front
= pad(filelineWidth(), nodep->fileline()->ascii() + ":") + " " + prefix + " +- ";
if (VN_IS(nodep, VarScope)) {
*m_ofp << front << "Variable: " << nodep->prettyName() << '\n';
@ -473,7 +475,7 @@ private:
if (level)
*m_ofp << V3OutFile::indentSpaces(filelineWidth()) << " " << prefix << nextsep << "\n";
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
if (CdcLogicVertex* const vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
// Now that we've printed a path with this hazard, don't bother to print any more
// Otherwise, we'd get a path for almost every destination flop
vvertexp->clearHazard();
@ -499,7 +501,7 @@ private:
UINFO(9, " Trace Direction " << (traceDests ? "dst" : "src") << endl);
m_graph.userClearVertices(); // user1: bool - was analyzed
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
if (CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
UINFO(9, " Trace One edge: " << vvertexp << endl);
edgeDomainRecurse(vvertexp, traceDests, 0);
}
@ -514,8 +516,8 @@ private:
std::deque<string> report; // Sort output by name
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
AstVar* varp = vvertexp->varScp()->varp();
if (const CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
const AstVar* const varp = vvertexp->varScp()->varp();
{
string what = "wire";
if (varp->isPrimaryIO()) what = varp->direction().prettyName();
@ -558,11 +560,11 @@ private:
} // Fully computed
std::set<AstSenTree*> senouts; // List of all sensitivities for new signal
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
if (const CdcLogicVertex* const vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
if (vvertexp) {} // Unused
} else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
} else if (const CdcVarVertex* const vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
// If primary I/O, give it domain of the input
AstVar* varp = vvertexp->varScp()->varp();
const AstVar* const varp = vvertexp->varScp()->varp();
if (varp->isPrimaryIO() && varp->isNonOutput() && !traceDests) {
senouts.insert(new AstSenTree(
varp->fileline(), new AstSenItem(varp->fileline(), AstSenItem::Combo())));
@ -572,13 +574,14 @@ private:
// Now combine domains of sources/dests
if (traceDests) {
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
CdcEitherVertex* eToVertexp = static_cast<CdcEitherVertex*>(edgep->top());
CdcEitherVertex* const eToVertexp = static_cast<CdcEitherVertex*>(edgep->top());
edgeDomainRecurse(eToVertexp, traceDests, level + 1);
if (eToVertexp->dstDomainp()) senouts.insert(eToVertexp->dstDomainp());
}
} else {
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
CdcEitherVertex* const eFromVertexp
= static_cast<CdcEitherVertex*>(edgep->fromp());
edgeDomainRecurse(eFromVertexp, traceDests, level + 1);
if (eFromVertexp->srcDomainp()) senouts.insert(eFromVertexp->srcDomainp());
}
@ -599,7 +602,7 @@ private:
}
}
// If multiple domains need to do complicated optimizations
if (senedited) senoutp = VN_CAST(V3Const::constifyExpensiveEdit(senoutp), SenTree);
if (senedited) senoutp = VN_AS(V3Const::constifyExpensiveEdit(senoutp), SenTree);
if (traceDests) {
vertexp->dstDomainSet(true); // Note it's set - domainp may be null, so can't use that
vertexp->dstDomainp(senoutp);
@ -653,9 +656,9 @@ private:
virtual void visit(AstNodeVarRef* nodep) override {
if (m_scopep) {
UASSERT_OBJ(m_logicVertexp, nodep, "Var ref not under a logic block");
AstVarScope* varscp = nodep->varScopep();
AstVarScope* const varscp = nodep->varScopep();
UASSERT_OBJ(varscp, nodep, "Var didn't get varscoped in V3Scope.cpp");
CdcVarVertex* varvertexp = makeVarVertex(varscp);
CdcVarVertex* const varvertexp = makeVarVertex(varscp);
UINFO(5, " VARREF to " << varscp << endl);
// We use weight of one for normal edges,
// Weight of CDC_WEIGHT_ASYNC to indicate feeds async (for reporting)
@ -758,5 +761,5 @@ public:
void V3Cdc::cdcAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
CdcVisitor visitor{nodep};
{ CdcVisitor{nodep}; }
}

View File

@ -71,7 +71,7 @@ public:
// Each change detection function needs at least one AstChangeDet
// to ensure that V3EmitC outputs the necessary code.
maybeCreateMidChg();
m_chgFuncp->addStmtsp(new AstChangeDet{m_scopetopp->fileline(), nullptr, nullptr, false});
m_chgFuncp->addStmtsp(new AstChangeDet{m_scopetopp->fileline(), nullptr, nullptr});
}
void maybeCreateMidChg() {
// Don't create an extra function call if splitting is disabled
@ -94,7 +94,7 @@ public:
if (!m_tlChgFuncp->stmtsp()) {
m_tlChgFuncp->addStmtsp(new AstCReturn{m_scopetopp->fileline(), callp});
} else {
AstCReturn* const returnp = VN_CAST(m_tlChgFuncp->stmtsp(), CReturn);
AstCReturn* const returnp = VN_AS(m_tlChgFuncp->stmtsp(), CReturn);
UASSERT_OBJ(returnp, m_scopetopp, "Lost CReturn in top change function");
// This is currently using AstLogOr which will shortcut the
// evaluation if any function returns true. This is likely what
@ -146,7 +146,7 @@ private:
m_statep->maybeCreateChgFuncp();
AstChangeDet* const changep = new AstChangeDet{
m_vscp->fileline(), m_varEqnp->cloneTree(true), m_newRvEqnp->cloneTree(true), false};
m_vscp->fileline(), m_varEqnp->cloneTree(true), m_newRvEqnp->cloneTree(true)};
m_statep->m_chgFuncp->addStmtsp(changep);
AstAssign* const initp = new AstAssign{m_vscp->fileline(), m_newLvEqnp->cloneTree(true),
m_varEqnp->cloneTree(true)};
@ -154,7 +154,7 @@ private:
// Later code will expand words which adds to GCC compile time,
// so add penalty based on word width also
EmitCBaseCounterVisitor visitor{initp};
const EmitCBaseCounterVisitor visitor{initp};
m_statep->m_numStmts += visitor.count() + m_varEqnp->widthWords();
}
@ -214,8 +214,8 @@ public:
m_detects = 0;
{
AstVar* const varp = m_vscp->varp();
string newvarname{"__Vchglast__" + m_vscp->scopep()->nameDotless() + "__"
+ varp->shortName()};
const string newvarname{"__Vchglast__" + m_vscp->scopep()->nameDotless() + "__"
+ varp->shortName()};
// Create: VARREF(_last)
// ASSIGN(VARREF(_last), VARREF(var))
// ...
@ -247,17 +247,17 @@ private:
// NODE STATE
// Entire netlist:
// AstVarScope::user1() -> bool. True indicates processed
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// STATE
ChangedState* m_statep; // Shared state across visitors
ChangedState* const m_statep; // Shared state across visitors
// METHODS
VL_DEBUG_FUNC; // Declare debug()
void genChangeDet(AstVarScope* vscp) {
vscp->v3warn(IMPERFECTSCH, "Imperfect scheduling of variable: " << vscp->prettyNameQ());
ChangedInsertVisitor visitor{vscp, m_statep};
{ ChangedInsertVisitor{vscp, m_statep}; }
}
// VISITORS
@ -304,7 +304,7 @@ void V3Changed::changedAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{
ChangedState state;
ChangedVisitor visitor{nodep, &state};
ChangedVisitor{nodep, &state};
} // Destruct before checking
V3Global::dumpCheckGlobalTree("changed", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -32,11 +32,11 @@
class ClassVisitor final : public AstNVisitor {
private:
// MEMBERS
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
string m_prefix; // String prefix to add to name based on hier
AstScope* m_classScopep = nullptr; // Package moving scopes into
const AstScope* m_classScopep = nullptr; // Package moving scopes into
AstScope* m_packageScopep = nullptr; // Class package scope
AstNodeFTask* m_ftaskp = nullptr; // Current task
const AstNodeFTask* m_ftaskp = nullptr; // Current task
std::vector<std::pair<AstNode*, AstScope*>> m_moves;
// NODE STATE
@ -53,27 +53,30 @@ private:
v3Global.rootp()->addModulep(nodep);
// Make containing package
// Note origName is the same as the class origName so errors look correct
AstClassPackage* packagep = new AstClassPackage(nodep->fileline(), nodep->origName());
AstClassPackage* const packagep
= new AstClassPackage(nodep->fileline(), nodep->origName());
packagep->name(nodep->name() + "__Vclpkg");
nodep->classOrPackagep(packagep);
packagep->classp(nodep);
v3Global.rootp()->addModulep(packagep);
// Add package to hierarchy
AstCell* cellp = new AstCell(packagep->fileline(), packagep->fileline(), packagep->name(),
packagep->name(), nullptr, nullptr, nullptr);
AstCell* const cellp
= new AstCell(packagep->fileline(), packagep->fileline(), packagep->name(),
packagep->name(), nullptr, nullptr, nullptr);
cellp->modp(packagep);
v3Global.rootp()->topModulep()->addStmtp(cellp);
// Find class's scope
// Alternative would be to move this and related to V3Scope
AstScope* classScopep = nullptr;
const AstScope* classScopep = nullptr;
for (AstNode* itp = nodep->stmtsp(); itp; itp = itp->nextp()) {
if ((classScopep = VN_CAST(itp, Scope))) break;
}
UASSERT_OBJ(classScopep, nodep, "No scope under class");
// Add scope
AstScope* scopep = new AstScope(nodep->fileline(), packagep, classScopep->name(),
classScopep->aboveScopep(), classScopep->aboveCellp());
AstScope* const scopep
= new AstScope(nodep->fileline(), packagep, classScopep->name(),
classScopep->aboveScopep(), classScopep->aboveCellp());
packagep->addStmtp(scopep);
// Iterate
VL_RESTORER(m_prefix);
@ -141,8 +144,9 @@ public:
if (VN_IS(moved.first, NodeFTask)) {
moved.second->addActivep(moved.first->unlinkFrBack());
} else if (VN_IS(moved.first, Var)) {
AstVarScope* scopep = VN_CAST(moved.first->user1p(), VarScope);
moved.second->addVarp(scopep->unlinkFrBack());
AstVarScope* const scopep = VN_AS(moved.first->user1p(), VarScope);
scopep->unlinkFrBack();
moved.second->addVarp(scopep);
}
}
}
@ -153,6 +157,6 @@ public:
void V3Class::classAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ ClassVisitor visitor{nodep}; } // Destruct before checking
{ ClassVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("class", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -42,15 +42,15 @@ private:
// AstNode::user() -> CleanState. For this node, 0==UNKNOWN
// AstNode::user2() -> bool. True indicates widthMin has been propagated
// AstNodeDType::user3() -> AstNodeDType*. Alternative node with C size
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
const AstUser1InUse m_inuser1;
const AstUser2InUse m_inuser2;
const AstUser3InUse m_inuser3;
// TYPES
enum CleanState : uint8_t { CS_UNKNOWN, CS_CLEAN, CS_DIRTY };
// STATE
AstNodeModule* m_modp = nullptr;
const AstNodeModule* m_modp = nullptr;
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@ -67,16 +67,16 @@ private:
}
void setCppWidth(AstNode* nodep) {
nodep->user2(true); // Don't resize it again
AstNodeDType* old_dtypep = nodep->dtypep();
AstNodeDType* const old_dtypep = nodep->dtypep();
const int width = cppWidth(nodep); // widthMin is unchanged
if (old_dtypep->width() != width) {
// Since any given dtype's cppWidth() is the same, we can just
// remember one conversion for each, and reuse it
if (AstNodeDType* new_dtypep = VN_CAST(old_dtypep->user3p(), NodeDType)) {
if (AstNodeDType* const new_dtypep = VN_CAST(old_dtypep->user3p(), NodeDType)) {
nodep->dtypep(new_dtypep);
} else {
nodep->dtypeChgWidth(width, nodep->widthMin());
AstNodeDType* new_dtypep2 = nodep->dtypep();
AstNodeDType* const new_dtypep2 = nodep->dtypep();
UASSERT_OBJ(new_dtypep2 != old_dtypep, nodep,
"Dtype didn't change when width changed");
old_dtypep->user3p(new_dtypep2); // Remember for next time
@ -126,7 +126,7 @@ private:
computeCppWidth(nodep);
V3Number mask(nodep, cppWidth(nodep));
mask.setMask(nodep->widthMin());
AstNode* cleanp
AstNode* const cleanp
= new AstAnd(nodep->fileline(), new AstConst(nodep->fileline(), mask), nodep);
cleanp->dtypeFrom(nodep); // Otherwise the AND normally picks LHS
relinkHandle.relink(cleanp);
@ -138,7 +138,7 @@ private:
void ensureCleanAndNext(AstNode* nodep) {
// Editing list, careful looping!
for (AstNode* exprp = nodep; exprp;) {
AstNode* nextp = exprp->nextp();
AstNode* const nextp = exprp->nextp();
ensureClean(exprp);
exprp = nextp;
}
@ -314,6 +314,6 @@ public:
void V3Clean::cleanAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CleanVisitor visitor{nodep}; } // Destruct before checking
{ CleanVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("clean", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -73,11 +73,11 @@ private:
// NODE STATE
// Cleared each Module:
// AstVarScope::user1p() -> AstVarScope*. Temporary signal that was created.
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// STATE
AstNodeModule* m_modp = nullptr; // Current module
AstTopScope* m_topScopep = nullptr; // Current top scope
const AstTopScope* m_topScopep = nullptr; // Current top scope
AstScope* m_scopep = nullptr; // Current scope
AstCFunc* m_evalFuncp = nullptr; // Top eval function we are creating
AstCFunc* m_initFuncp = nullptr; // Top initial function we are creating
@ -92,30 +92,30 @@ private:
AstVarScope* getCreateLastClk(AstVarScope* vscp) {
if (vscp->user1p()) return static_cast<AstVarScope*>(vscp->user1p());
AstVar* varp = vscp->varp();
const AstVar* const varp = vscp->varp();
if (!varp->width1()) {
varp->v3warn(E_UNSUPPORTED, "Unsupported: Clock edge on non-single bit signal: "
<< varp->prettyNameQ());
}
string newvarname
const string newvarname
= (string("__Vclklast__") + vscp->scopep()->nameDotless() + "__" + varp->name());
AstVar* newvarp = new AstVar(vscp->fileline(), AstVarType::MODULETEMP, newvarname,
VFlagLogicPacked(), 1);
AstVar* const newvarp = new AstVar(vscp->fileline(), AstVarType::MODULETEMP, newvarname,
VFlagLogicPacked(), 1);
newvarp->noReset(true); // Reset by below assign
m_modp->addStmtp(newvarp);
AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopep, newvarp);
AstVarScope* const newvscp = new AstVarScope(vscp->fileline(), m_scopep, newvarp);
vscp->user1p(newvscp);
m_scopep->addVarp(newvscp);
// Add init
AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, VAccess::READ);
if (v3Global.opt.xInitialEdge()) fromp = new AstNot(fromp->fileline(), fromp);
AstNode* newinitp = new AstAssign(
AstNode* const newinitp = new AstAssign(
vscp->fileline(), new AstVarRef(newvarp->fileline(), newvscp, VAccess::WRITE), fromp);
addToInitial(newinitp);
// At bottom, assign them
AstAssign* finalp = new AstAssign(vscp->fileline(),
new AstVarRef(vscp->fileline(), newvscp, VAccess::WRITE),
new AstVarRef(vscp->fileline(), vscp, VAccess::READ));
AstAssign* const finalp = new AstAssign(
vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, VAccess::WRITE),
new AstVarRef(vscp->fileline(), vscp, VAccess::READ));
m_evalFuncp->addFinalsp(finalp);
//
UINFO(4, "New Last: " << newvscp << endl);
@ -137,16 +137,16 @@ private:
return nullptr;
}
UASSERT_OBJ(nodep->varrefp(), nodep, "No clock found on sense item");
AstVarScope* clkvscp = nodep->varrefp()->varScopep();
AstVarScope* const clkvscp = nodep->varrefp()->varScopep();
if (nodep->edgeType() == VEdgeType::ET_POSEDGE) {
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
AstVarScope* const lastVscp = getCreateLastClk(clkvscp);
newp = new AstAnd(
nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), VAccess::READ),
new AstNot(nodep->fileline(),
new AstVarRef(nodep->fileline(), lastVscp, VAccess::READ)));
} else if (nodep->edgeType() == VEdgeType::ET_NEGEDGE) {
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
AstVarScope* const lastVscp = getCreateLastClk(clkvscp);
newp = new AstAnd(
nodep->fileline(),
new AstNot(nodep->fileline(),
@ -154,7 +154,7 @@ private:
VAccess::READ)),
new AstVarRef(nodep->fileline(), lastVscp, VAccess::READ));
} else if (nodep->edgeType() == VEdgeType::ET_BOTHEDGE) {
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
AstVarScope* const lastVscp = getCreateLastClk(clkvscp);
newp = new AstXor(
nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), VAccess::READ),
@ -172,7 +172,7 @@ private:
AstNode* createSenseEquation(AstSenItem* nodesp) {
// Nodep may be a list of elements; we need to walk it
AstNode* senEqnp = nullptr;
for (AstSenItem* senp = nodesp; senp; senp = VN_CAST(senp->nextp(), SenItem)) {
for (AstSenItem* senp = nodesp; senp; senp = VN_AS(senp->nextp(), SenItem)) {
AstNode* const senOnep = createSenItemEquation(senp);
if (senEqnp) {
// Add new OR to the sensitivity list equation
@ -184,9 +184,9 @@ private:
return senEqnp;
}
AstIf* makeActiveIf(AstSenTree* sensesp) {
AstNode* senEqnp = createSenseEquation(sensesp->sensesp());
AstNode* const senEqnp = createSenseEquation(sensesp->sensesp());
UASSERT_OBJ(senEqnp, sensesp, "No sense equation, shouldn't be in sequent activation.");
AstIf* newifp = new AstIf(sensesp->fileline(), senEqnp, nullptr, nullptr);
AstIf* const newifp = new AstIf(sensesp->fileline(), senEqnp, nullptr, nullptr);
return newifp;
}
void clearLastSen() {
@ -215,11 +215,11 @@ private:
AstCFunc* funcp = nullptr;
// Unlink all statements, then add item by item to new sub-functions
AstBegin* tempp = new AstBegin{ofuncp->fileline(), "[EditWrapper]",
ofuncp->stmtsp()->unlinkFrBackWithNext()};
AstBegin* const tempp = new AstBegin{ofuncp->fileline(), "[EditWrapper]",
ofuncp->stmtsp()->unlinkFrBackWithNext()};
if (ofuncp->finalsp()) tempp->addStmtsp(ofuncp->finalsp()->unlinkFrBackWithNext());
while (tempp->stmtsp()) {
AstNode* itemp = tempp->stmtsp()->unlinkFrBack();
AstNode* const itemp = tempp->stmtsp()->unlinkFrBack();
const int stmts = EmitCBaseCounterVisitor(itemp).count();
if (!funcp || (func_stmts + stmts) > v3Global.opt.outputSplitCFuncs()) {
// Make a new function
@ -231,7 +231,7 @@ private:
funcp->slow(ofuncp->slow());
m_topScopep->scopep()->addActivep(funcp);
//
AstCCall* callp = new AstCCall{funcp->fileline(), funcp};
AstCCall* const callp = new AstCCall{funcp->fileline(), funcp};
ofuncp->addStmtsp(callp);
func_stmts = 0;
}
@ -289,7 +289,7 @@ private:
// UINFO(4, " SCOPE " << nodep << endl);
m_scopep = nodep;
iterateChildren(nodep);
if (AstNode* movep = nodep->finalClksp()) {
if (AstNode* const movep = nodep->finalClksp()) {
UASSERT_OBJ(m_topScopep, nodep, "Final clocks under non-top scope");
movep->unlinkFrBackWithNext();
m_evalFuncp->addFinalsp(movep);
@ -297,7 +297,7 @@ private:
m_scopep = nullptr;
}
virtual void visit(AstNodeProcedure* nodep) override {
if (AstNode* stmtsp = nodep->bodysp()) {
if (AstNode* const stmtsp = nodep->bodysp()) {
stmtsp->unlinkFrBackWithNext();
nodep->addNextHere(stmtsp);
}
@ -307,12 +307,12 @@ private:
// nodep->dumpTree(cout, "ct:");
// COVERTOGGLE(INC, ORIG, CHANGE) ->
// IF(ORIG ^ CHANGE) { INC; CHANGE = ORIG; }
AstNode* incp = nodep->incp()->unlinkFrBack();
AstNode* origp = nodep->origp()->unlinkFrBack();
AstNode* changeWrp = nodep->changep()->unlinkFrBack();
AstNode* changeRdp = ConvertWriteRefsToRead::main(changeWrp->cloneTree(false));
AstIf* newp = new AstIf(nodep->fileline(), new AstXor(nodep->fileline(), origp, changeRdp),
incp, nullptr);
AstNode* const incp = nodep->incp()->unlinkFrBack();
AstNode* const origp = nodep->origp()->unlinkFrBack();
AstNode* const changeWrp = nodep->changep()->unlinkFrBack();
AstNode* const changeRdp = ConvertWriteRefsToRead::main(changeWrp->cloneTree(false));
AstIf* const newp = new AstIf(
nodep->fileline(), new AstXor(nodep->fileline(), origp, changeRdp), incp, nullptr);
// 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.
@ -325,7 +325,7 @@ private:
// Link to global function
if (nodep->formCallTree()) {
UINFO(4, " formCallTree " << nodep << endl);
AstCCall* callp = new AstCCall(nodep->fileline(), nodep);
AstCCall* const callp = new AstCCall(nodep->fileline(), nodep);
m_finalFuncp->addStmtsp(callp);
}
}
@ -353,7 +353,7 @@ private:
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
} else if (m_mtaskBodyp) {
UINFO(4, " TR ACTIVE " << nodep << endl);
AstNode* stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
AstNode* const stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
if (nodep->hasClocked()) {
UASSERT_OBJ(!nodep->hasInitial(), nodep,
"Initial block should not have clock sensitivity");
@ -378,7 +378,7 @@ private:
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
} else {
UINFO(4, " ACTIVE " << nodep << endl);
AstNode* stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
AstNode* const stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
if (nodep->hasClocked()) {
// Remember the latest sensitivity so we can compare it next time
UASSERT_OBJ(!nodep->hasInitial(), nodep,
@ -412,8 +412,8 @@ private:
}
}
virtual void visit(AstExecGraph* nodep) override {
for (m_mtaskBodyp = VN_CAST(nodep->op1p(), MTaskBody); m_mtaskBodyp;
m_mtaskBodyp = VN_CAST(m_mtaskBodyp->nextp(), MTaskBody)) {
for (m_mtaskBodyp = VN_AS(nodep->op1p(), MTaskBody); m_mtaskBodyp;
m_mtaskBodyp = VN_AS(m_mtaskBodyp->nextp(), MTaskBody)) {
clearLastSen();
iterate(m_mtaskBodyp);
}
@ -444,6 +444,6 @@ public:
void V3Clock::clockAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ ClockVisitor visitor{nodep}; } // Destruct before checking
{ ClockVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("clock", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -121,7 +121,7 @@ class CombineVisitor final : CombBaseVisitor {
private:
// NODE STATE
// Entire netlist:
AstUser3InUse m_user3InUse; // Marks replaced AstCFuncs
const AstUser3InUse m_user3InUse; // Marks replaced AstCFuncs
// AstUser4InUse part of V3Hasher in V3DupFinder
// STATE
@ -132,7 +132,7 @@ private:
// METHODS
void walkEmptyFuncs() {
for (const auto& itr : m_dupFinder) {
AstCFunc* const oldfuncp = VN_CAST(itr.second, CFunc);
AstCFunc* const oldfuncp = VN_AS(itr.second, CFunc);
UASSERT_OBJ(oldfuncp, itr.second, "Not a CFunc in hash");
if (!oldfuncp->emptyBody()) continue;
UASSERT_OBJ(!oldfuncp->dontCombine(), oldfuncp,
@ -152,14 +152,14 @@ private:
// Do non-slow first as then favors naming functions based on fast name
for (const bool slow : {false, true}) {
for (auto newIt = m_dupFinder.begin(); newIt != m_dupFinder.end(); ++newIt) {
AstCFunc* const newfuncp = VN_CAST(newIt->second, CFunc);
AstCFunc* const newfuncp = VN_AS(newIt->second, CFunc);
UASSERT_OBJ(newfuncp, newIt->second, "Not a CFunc in hash");
if (newfuncp->user3()) continue; // Already replaced
if (newfuncp->slow() != slow) continue;
auto oldIt = newIt;
++oldIt; // Skip over current position
for (; oldIt != m_dupFinder.end(); ++oldIt) {
AstCFunc* const oldfuncp = VN_CAST(oldIt->second, CFunc);
AstCFunc* const oldfuncp = VN_AS(oldIt->second, CFunc);
UASSERT_OBJ(oldfuncp, oldIt->second, "Not a CFunc in hash");
UASSERT_OBJ(newfuncp != oldfuncp, newfuncp,
"Same function hashed multiple times");
@ -223,6 +223,6 @@ public:
void V3Combine::combineAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CombineVisitor visitor{nodep}; } // Destruct before checking
{ CombineVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("combine", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -64,7 +64,7 @@ static void makeToStringMiddle(AstClass* nodep) {
funcp->addStmtsp(new AstCStmt{nodep->fileline(), "std::string out;\n"});
std::string comma;
for (AstNode* itemp = nodep->membersp(); itemp; itemp = itemp->nextp()) {
if (auto* const varp = VN_CAST(itemp, Var)) {
if (const auto* const varp = VN_CAST(itemp, Var)) {
if (!varp->isParam()) {
string stmt = "out += \"";
stmt += comma;
@ -109,7 +109,7 @@ void V3Common::commonAll() {
// NODE STATE
// Entire netlist:
// AstClass::user1() -> bool. True if class needs to_string dumper
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// Create ToString methods
makeVlToString(classp);
makeToString(classp);

View File

@ -103,7 +103,7 @@ public:
// Apply all attributes to the variable
void apply(AstVar* varp) {
for (const_iterator it = begin(); it != end(); ++it) {
AstNode* newp = new AstAttrOf(varp->fileline(), it->m_type);
AstNode* const newp = new AstAttrOf(varp->fileline(), it->m_type);
varp->addAttrsp(newp);
if (it->m_type == AstAttrType::VAR_PUBLIC_FLAT_RW && it->m_sentreep) {
newp->addNext(new AstAlwaysPublic(varp->fileline(), it->m_sentreep, nullptr));
@ -190,13 +190,13 @@ public:
void apply(AstNodeModule* modp) {
if (m_inline) {
AstPragmaType type
const AstPragmaType type
= m_inlineValue ? AstPragmaType::INLINE_MODULE : AstPragmaType::NO_INLINE_MODULE;
AstNode* nodep = new AstPragma(modp->fileline(), type);
AstNode* const nodep = new AstPragma(modp->fileline(), type);
modp->addStmtp(nodep);
}
for (auto it = m_modPragmas.cbegin(); it != m_modPragmas.cend(); ++it) {
AstNode* nodep = new AstPragma(modp->fileline(), *it);
AstNode* const nodep = new AstPragma(modp->fileline(), *it);
modp->addStmtp(nodep);
}
}
@ -223,9 +223,9 @@ using V3ConfigModuleResolver = V3ConfigWildcardResolver<V3ConfigModule>;
// lint/coverage/tracing on/off
class V3ConfigIgnoresLine final {
public:
int m_lineno; // Line number to make change at
V3ErrorCode m_code; // Error code
bool m_on; // True to enable message
const int m_lineno; // Line number to make change at
const V3ErrorCode m_code; // Error code
const bool m_on; // True to enable message
V3ConfigIgnoresLine(V3ErrorCode code, int lineno, bool on)
: m_lineno{lineno}
, m_code{code}
@ -502,7 +502,7 @@ void V3Config::applyFTask(AstNodeModule* modulep, AstNodeFTask* ftaskp) {
const string& modname = modulep->name();
V3ConfigModule* modp = V3ConfigResolver::s().modules().resolve(modname);
if (!modp) return;
V3ConfigFTask* ftp = modp->ftasks().resolve(ftaskp->name());
const V3ConfigFTask* const ftp = modp->ftasks().resolve(ftaskp->name());
if (ftp) ftp->apply(ftaskp);
}

View File

@ -48,7 +48,7 @@ public:
static void applyFTask(AstNodeModule* modulep, AstNodeFTask* ftaskp);
static void applyVarAttr(AstNodeModule* modulep, AstNodeFTask* ftaskp, AstVar* varp);
static uint64_t getProfileData(const string& model, const string& key);
static vluint64_t getProfileData(const string& model, const string& key);
static FileLine* getProfileDataFileLine();
static bool waive(FileLine* filelinep, V3ErrorCode code, const string& message);
};

File diff suppressed because it is too large Load Diff

View File

@ -43,7 +43,7 @@ private:
using LinenoSet = std::set<int>;
struct ToggleEnt {
string m_comment; // Comment for coverage dump
const string m_comment; // Comment for coverage dump
AstNode* m_varRefp; // How to get to this element
AstNode* m_chgRefp; // How to get to this element
ToggleEnt(const string& comment, AstNode* vp, AstNode* cp)
@ -73,7 +73,7 @@ private:
// NODE STATE
// Entire netlist:
// AstIf::user1() -> bool. True indicates ifelse processed
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// STATE
CheckState m_state; // State save-restored on each new coverage scope/block
@ -116,20 +116,20 @@ private:
// Someday the user might be allowed to specify a different page suffix
const string page = page_prefix + "/" + m_modp->prettyName();
AstCoverDecl* declp = new AstCoverDecl(fl, page, comment, linescov, offset);
AstCoverDecl* const declp = new AstCoverDecl(fl, page, comment, linescov, offset);
declp->hier(hier);
m_modp->addStmtp(declp);
UINFO(9, "new " << declp << endl);
AstCoverInc* incp = new AstCoverInc(fl, declp);
AstCoverInc* const incp = new AstCoverInc(fl, declp);
if (!trace_var_name.empty() && v3Global.opt.traceCoverage()) {
AstVar* varp = new AstVar(incp->fileline(), AstVarType::MODULETEMP, trace_var_name,
incp->findUInt32DType());
AstVar* const varp = new AstVar(incp->fileline(), AstVarType::MODULETEMP,
trace_var_name, incp->findUInt32DType());
varp->trace(true);
varp->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true);
m_modp->addStmtp(varp);
UINFO(5, "New coverage trace: " << varp << endl);
AstAssign* assp = new AstAssign(
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)));
@ -209,7 +209,7 @@ private:
// VISITORS - BOTH
virtual void visit(AstNodeModule* nodep) override {
AstNodeModule* origModp = m_modp;
const AstNodeModule* const origModp = m_modp;
VL_RESTORER(m_modp);
VL_RESTORER(m_state);
{
@ -240,14 +240,14 @@ private:
iterateChildren(nodep);
if (m_state.lineCoverageOn(nodep)) {
lineTrack(nodep);
AstNode* newp
AstNode* const newp
= newCoverInc(nodep->fileline(), "", "v_line", "block",
linesCov(m_state, nodep), 0, traceNameForLine(nodep, "block"));
if (AstNodeProcedure* itemp = VN_CAST(nodep, NodeProcedure)) {
if (AstNodeProcedure* const itemp = VN_CAST(nodep, NodeProcedure)) {
itemp->addStmtp(newp);
} else if (AstNodeFTask* itemp = VN_CAST(nodep, NodeFTask)) {
} else if (AstNodeFTask* const itemp = VN_CAST(nodep, NodeFTask)) {
itemp->addStmtsp(newp);
} else if (AstWhile* itemp = VN_CAST(nodep, While)) {
} else if (AstWhile* const itemp = VN_CAST(nodep, While)) {
itemp->addBodysp(newp);
} else {
nodep->v3fatalSrc("Bad node type");
@ -261,7 +261,7 @@ private:
iterateChildren(nodep);
if (m_modp && !m_inToggleOff && !m_state.m_inModOff && nodep->fileline()->coverageOn()
&& v3Global.opt.coverageToggle()) {
const char* disablep = varIgnoreToggle(nodep);
const char* const disablep = varIgnoreToggle(nodep);
if (disablep) {
UINFO(4, " Disable Toggle: " << disablep << " " << nodep << endl);
} else {
@ -279,7 +279,7 @@ private:
// Add signal to hold the old value
const string newvarname = string("__Vtogcov__") + nodep->shortName();
AstVar* chgVarp
AstVar* const chgVarp
= new AstVar(nodep->fileline(), AstVarType::MODULETEMP, newvarname, nodep);
chgVarp->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true);
m_modp->addStmtp(chgVarp);
@ -298,7 +298,7 @@ private:
}
void toggleVarBottom(const ToggleEnt& above, const AstVar* varp) {
AstCoverToggle* newp = new AstCoverToggle(
AstCoverToggle* const newp = new AstCoverToggle(
varp->fileline(),
newCoverInc(varp->fileline(), "", "v_toggle", varp->name() + above.m_comment, "", 0,
""),
@ -308,7 +308,7 @@ private:
void toggleVarRecurse(AstNodeDType* dtypep, int depth, // per-iteration
const ToggleEnt& above, AstVar* varp, AstVar* chgVarp) { // Constant
if (const AstBasicDType* bdtypep = VN_CAST(dtypep, BasicDType)) {
if (const AstBasicDType* const bdtypep = VN_CAST(dtypep, BasicDType)) {
if (bdtypep->isRanged()) {
for (int index_docs = bdtypep->lo(); index_docs < bdtypep->hi() + 1;
++index_docs) {
@ -324,7 +324,7 @@ private:
} else {
toggleVarBottom(above, varp);
}
} else if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
} else if (const AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
for (int index_docs = adtypep->lo(); index_docs <= adtypep->hi(); ++index_docs) {
const int index_code = index_docs - adtypep->lo();
ToggleEnt newent(above.m_comment + string("[") + cvtToStr(index_docs) + "]",
@ -336,9 +336,9 @@ private:
chgVarp);
newent.cleanup();
}
} else if (AstPackArrayDType* adtypep = VN_CAST(dtypep, PackArrayDType)) {
} else if (const AstPackArrayDType* const adtypep = VN_CAST(dtypep, PackArrayDType)) {
for (int index_docs = adtypep->lo(); index_docs <= adtypep->hi(); ++index_docs) {
AstNodeDType* subtypep = adtypep->subDTypep()->skipRefp();
const AstNodeDType* const subtypep = adtypep->subDTypep()->skipRefp();
const int index_code = index_docs - adtypep->lo();
ToggleEnt newent(above.m_comment + string("[") + cvtToStr(index_docs) + "]",
new AstSel(varp->fileline(), above.m_varRefp->cloneTree(true),
@ -349,11 +349,11 @@ private:
chgVarp);
newent.cleanup();
}
} else if (AstStructDType* adtypep = VN_CAST(dtypep, StructDType)) {
} else if (const AstStructDType* const adtypep = VN_CAST(dtypep, StructDType)) {
// For now it's packed, so similar to array
for (AstMemberDType* itemp = adtypep->membersp(); itemp;
itemp = VN_CAST(itemp->nextp(), MemberDType)) {
AstNodeDType* subtypep = itemp->subDTypep()->skipRefp();
itemp = VN_AS(itemp->nextp(), MemberDType)) {
AstNodeDType* const subtypep = itemp->subDTypep()->skipRefp();
const int index_code = itemp->lsb();
ToggleEnt newent(above.m_comment + string(".") + itemp->name(),
new AstSel(varp->fileline(), above.m_varRefp->cloneTree(true),
@ -363,10 +363,10 @@ private:
toggleVarRecurse(subtypep, depth + 1, newent, varp, chgVarp);
newent.cleanup();
}
} else if (AstUnionDType* adtypep = VN_CAST(dtypep, UnionDType)) {
} else if (const AstUnionDType* const adtypep = VN_CAST(dtypep, UnionDType)) {
// Arbitrarily handle only the first member of the union
if (AstMemberDType* itemp = adtypep->membersp()) {
AstNodeDType* subtypep = itemp->subDTypep()->skipRefp();
if (const AstMemberDType* const itemp = adtypep->membersp()) {
AstNodeDType* const subtypep = itemp->subDTypep()->skipRefp();
ToggleEnt newent(above.m_comment + string(".") + itemp->name(),
above.m_varRefp->cloneTree(true),
above.m_chgRefp->cloneTree(true));
@ -387,7 +387,7 @@ private:
// An else-if. When we iterate the if, use "elsif" marking
const bool elsif
= nodep->ifsp() && VN_IS(nodep->elsesp(), If) && !nodep->elsesp()->nextp();
if (elsif) VN_CAST(nodep->elsesp(), If)->user1(true);
if (elsif) VN_AS(nodep->elsesp(), If)->user1(true);
const bool first_elsif = !nodep->user1() && elsif;
const bool cont_elsif = nodep->user1() && elsif;
const bool final_elsif = nodep->user1() && !elsif && nodep->elsesp();
@ -543,6 +543,6 @@ public:
void V3Coverage::coverage(AstNetlist* rootp) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CoverageVisitor visitor{rootp}; } // Destruct before checking
{ CoverageVisitor{rootp}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("coverage", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -60,18 +60,18 @@ private:
const auto dupit = dupFinder.findDuplicate(nodep->origp());
if (dupit == dupFinder.end()) break;
//
AstNode* duporigp = dupit->second;
const AstNode* const duporigp = dupit->second;
// Note hashed will point to the original variable (what's
// duplicated), not the covertoggle, but we need to get back to the
// covertoggle which is immediately above, so:
AstCoverToggle* removep = VN_CAST(duporigp->backp(), CoverToggle);
AstCoverToggle* const removep = VN_AS(duporigp->backp(), CoverToggle);
UASSERT_OBJ(removep, nodep, "CoverageJoin duplicate of wrong type");
UINFO(8, " Orig " << nodep << " -->> " << nodep->incp()->declp() << endl);
UINFO(8, " dup " << removep << " -->> " << removep->incp()->declp() << endl);
// The CoverDecl the duplicate pointed to now needs to point to the
// original's data. I.e. the duplicate will get the coverage number
// from the non-duplicate
AstCoverDecl* datadeclp = nodep->incp()->declp()->dataDeclThisp();
AstCoverDecl* const datadeclp = nodep->incp()->declp()->dataDeclThisp();
removep->incp()->declp()->dataDeclp(datadeclp);
UINFO(8, " new " << removep->incp()->declp() << endl);
// Mark the found node as a duplicate of the first node
@ -114,6 +114,6 @@ public:
void V3CoverageJoin::coverageJoin(AstNetlist* rootp) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CoverageJoinVisitor visitor{rootp}; } // Destruct before checking
{ CoverageJoinVisitor{rootp}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("coveragejoin", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -76,7 +76,7 @@ private:
// AstVar::user1() -> int. Count of number of references
// AstVarScope::user1() -> int. Count of number of references
// AstNodeDType::user1() -> int. Count of number of references
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// TYPES
using AssignMap = std::multimap<AstVarScope*, AstNodeAssign*>;
@ -102,9 +102,9 @@ private:
void checkAll(AstNode* nodep) {
if (nodep != nodep->dtypep()) { // NodeDTypes reference themselves
if (AstNode* subnodep = nodep->dtypep()) subnodep->user1Inc();
if (AstNode* const subnodep = nodep->dtypep()) subnodep->user1Inc();
}
if (AstNode* subnodep = nodep->getChildDTypep()) subnodep->user1Inc();
if (AstNode* const subnodep = nodep->getChildDTypep()) subnodep->user1Inc();
}
void checkVarRef(AstNodeVarRef* nodep) {
if (nodep->classOrPackagep() && m_elimCells) nodep->classOrPackagep(nullptr);
@ -116,8 +116,8 @@ private:
) {
m_dtypesp.push_back(nodep);
}
if (AstNode* subnodep = nodep->virtRefDTypep()) subnodep->user1Inc();
if (AstNode* subnodep = nodep->virtRefDType2p()) subnodep->user1Inc();
if (AstNode* const subnodep = nodep->virtRefDTypep()) subnodep->user1Inc();
if (AstNode* const subnodep = nodep->virtRefDType2p()) subnodep->user1Inc();
}
// VISITORS
@ -129,7 +129,7 @@ private:
if (!nodep->dead()) {
iterateChildren(nodep);
checkAll(nodep);
if (AstClass* classp = VN_CAST(nodep, Class)) {
if (AstClass* const classp = VN_CAST(nodep, Class)) {
if (classp->extendsp()) classp->extendsp()->user1Inc();
if (classp->classOrPackagep()) classp->classOrPackagep()->user1Inc();
m_classesp.push_back(classp);
@ -282,7 +282,7 @@ private:
iterateAndNextNull(nodep->rhsp());
checkAll(nodep);
// Has to be direct assignment without any EXTRACTing.
AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef);
AstVarRef* const varrefp = VN_CAST(nodep->lhsp(), VarRef);
if (varrefp && !m_sideEffect
&& varrefp->varScopep()) { // For simplicity, we only remove post-scoping
m_assignMap.emplace(varrefp->varScopep(), nodep);
@ -310,7 +310,7 @@ private:
retry = false;
AstNodeModule* nextmodp;
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp = nextmodp) {
nextmodp = VN_CAST(modp->nextp(), NodeModule);
nextmodp = VN_AS(modp->nextp(), NodeModule);
if (modp->dead()
|| (modp->level() > 2 && modp->user1() == 0 && !modp->internal())) {
// > 2 because L1 is the wrapper, L2 is the top user module
@ -318,7 +318,7 @@ private:
// And its children may now be killable too; correct counts
// Recurse, as cells may not be directly under the module but in a generate
if (!modp->dead()) { // If was dead didn't increment user1's
DeadModVisitor visitor{modp};
DeadModVisitor{modp};
}
VL_DO_DANGLING(modp->unlinkFrBack()->deleteTree(), modp);
retry = true;
@ -338,7 +338,7 @@ private:
retry = false;
for (std::vector<AstScope*>::iterator it = m_scopesp.begin(); it != m_scopesp.end();
++it) {
AstScope* scp = *it;
AstScope* const scp = *it;
if (!scp) continue;
if (scp->user1() == 0) {
UINFO(4, " Dead AstScope " << scp << endl);
@ -364,7 +364,7 @@ private:
for (bool retry = true; retry;) {
retry = false;
for (auto& itr : m_classesp) {
if (AstClass* nodep = itr) { // nullptr if deleted earlier
if (AstClass* const nodep = itr) { // nullptr if deleted earlier
if (nodep->user1() == 0) {
if (nodep->extendsp()) nodep->extendsp()->user1Inc(-1);
if (nodep->classOrPackagep()) nodep->classOrPackagep()->user1Inc(-1);
@ -382,10 +382,10 @@ private:
for (AstVarScope* vscp : m_vscsp) {
if (vscp->user1() == 0) {
UINFO(4, " Dead " << vscp << endl);
std::pair<AssignMap::iterator, AssignMap::iterator> eqrange
const std::pair<AssignMap::iterator, AssignMap::iterator> eqrange
= m_assignMap.equal_range(vscp);
for (AssignMap::iterator itr = eqrange.first; itr != eqrange.second; ++itr) {
AstNodeAssign* assp = itr->second;
AstNodeAssign* const assp = itr->second;
UINFO(4, " Dead assign " << assp << endl);
assp->dtypep()->user1Inc(-1);
VL_DO_DANGLING(assp->unlinkFrBack()->deleteTree(), assp);
@ -398,7 +398,7 @@ private:
for (bool retry = true; retry;) {
retry = false;
for (std::vector<AstVar*>::iterator it = m_varsp.begin(); it != m_varsp.end(); ++it) {
AstVar* varp = *it;
AstVar* const varp = *it;
if (!varp) continue;
if (varp->user1() == 0) {
UINFO(4, " Dead " << varp << endl);
@ -411,14 +411,14 @@ private:
}
for (std::vector<AstNode*>::iterator it = m_dtypesp.begin(); it != m_dtypesp.end(); ++it) {
if ((*it)->user1() == 0) {
AstNodeUOrStructDType* classp;
const AstNodeUOrStructDType* classp;
// It's possible that there if a reference to each individual member, but
// not to the dtype itself. Check and don't remove the parent dtype if
// members are still alive.
if ((classp = VN_CAST((*it), NodeUOrStructDType))) {
bool cont = true;
for (AstMemberDType* memberp = classp->membersp(); memberp;
memberp = VN_CAST(memberp->nextp(), MemberDType)) {
memberp = VN_AS(memberp->nextp(), MemberDType)) {
if (memberp->user1() != 0) {
cont = false;
break;
@ -463,31 +463,31 @@ public:
void V3Dead::deadifyModules(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor visitor{nodep, false, false, false, false}; } // Destruct before checking
{ DeadVisitor{nodep, false, false, false, false}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadModules", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
}
void V3Dead::deadifyDTypes(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor visitor{nodep, false, true, false, false}; } // Destruct before checking
{ DeadVisitor{nodep, false, true, false, false}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadDtypes", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
void V3Dead::deadifyDTypesScoped(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor visitor{nodep, false, true, true, false}; } // Destruct before checking
{ DeadVisitor{nodep, false, true, true, false}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0,
v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
void V3Dead::deadifyAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor visitor{nodep, true, true, false, true}; } // Destruct before checking
{ DeadVisitor{nodep, true, true, false, true}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadAll", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}
void V3Dead::deadifyAllScoped(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DeadVisitor visitor{nodep, true, true, true, true}; } // Destruct before checking
{ DeadVisitor{nodep, true, true, true, true}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deadAllScoped", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -81,15 +81,15 @@ private:
// Cleared each scope/active:
// AstAssignDly::user3() -> AstVarScope*. __Vdlyvset__ created for this assign
// AstAlwaysPost::user3() -> AstVarScope*. __Vdlyvset__ last referenced in IF
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
AstUser4InUse m_inuser4;
AstUser5InUse m_inuser5;
const AstUser1InUse m_inuser1;
const AstUser2InUse m_inuser2;
const AstUser3InUse m_inuser3;
const AstUser4InUse m_inuser4;
const AstUser5InUse m_inuser5;
// STATE
AstActive* m_activep = nullptr; // Current activate
AstCFunc* m_cfuncp = nullptr; // Current public C Function
const AstCFunc* m_cfuncp = nullptr; // Current public C Function
AstAssignDly* m_nextDlyp = nullptr; // Next delayed assignment in a list of assignments
bool m_inDly = false; // True in delayed assignments
bool m_inLoop = false; // True in for loops
@ -104,16 +104,16 @@ private:
void markVarUsage(AstNodeVarRef* nodep, bool blocking) {
if (blocking) nodep->user5(true);
AstVarScope* vscp = nodep->varScopep();
AstVarScope* const vscp = nodep->varScopep();
// UINFO(4, " MVU " << blocking << " " << nodep << endl);
AstNode* lastrefp = vscp->user5p();
const AstNode* const lastrefp = vscp->user5p();
if (!lastrefp) {
vscp->user5p(nodep);
} else {
const bool last_was_blocking = lastrefp->user5();
if (last_was_blocking != blocking) {
AstNode* nonblockingp = blocking ? nodep : lastrefp;
AstNode* blockingp = blocking ? lastrefp : nodep;
const AstNode* const nonblockingp = blocking ? nodep : lastrefp;
const AstNode* const blockingp = blocking ? lastrefp : nodep;
vscp->v3warn(
BLKANDNBLK,
"Unsupported: Blocked and non-blocking assignments to same variable: "
@ -131,7 +131,7 @@ private:
// Because we've already scoped it, we may need to add both the AstVar and the AstVarScope
UASSERT_OBJ(oldvarscp->scopep(), oldvarscp, "Var unscoped");
AstVar* varp;
AstNodeModule* addmodp = oldvarscp->scopep()->modp();
AstNodeModule* const addmodp = oldvarscp->scopep()->modp();
// We need a new AstVar, but only one for all scopes, to match the new AstVarScope
const auto it = m_modVarMap.find(std::make_pair(addmodp, name));
if (it != m_modVarMap.end()) {
@ -152,13 +152,14 @@ private:
m_modVarMap.emplace(std::make_pair(addmodp, name), varp);
}
AstVarScope* varscp = new AstVarScope(oldvarscp->fileline(), oldvarscp->scopep(), varp);
AstVarScope* const varscp
= new AstVarScope(oldvarscp->fileline(), oldvarscp->scopep(), varp);
oldvarscp->scopep()->addVarp(varscp);
return varscp;
}
AstActive* createActivePost(AstVarRef* varrefp) {
AstActive* newactp
AstActive* const newactp
= new AstActive(varrefp->fileline(), "sequentdly", m_activep->sensesp());
// Was addNext(), but addNextHere() avoids a linear search.
m_activep->addNextHere(newactp);
@ -184,11 +185,11 @@ private:
UINFO(4, " Act: " << m_activep << endl);
UINFO(4, " Act: " << oldactivep << endl);
// Make a new sensitivity list, which is the combination of both blocks
AstSenItem* sena = m_activep->sensesp()->sensesp()->cloneTree(true);
AstSenItem* senb = oldactivep->sensesp()->sensesp()->cloneTree(true);
AstSenTree* treep = new AstSenTree(m_activep->fileline(), sena);
AstSenItem* const sena = m_activep->sensesp()->sensesp()->cloneTree(true);
AstSenItem* const senb = oldactivep->sensesp()->sensesp()->cloneTree(true);
AstSenTree* const treep = new AstSenTree(m_activep->fileline(), sena);
if (senb) treep->addSensesp(senb);
if (AstSenTree* storep = oldactivep->sensesStorep()) {
if (AstSenTree* const storep = oldactivep->sensesStorep()) {
storep->unlinkFrBack();
pushDeletep(storep);
}
@ -203,13 +204,13 @@ private:
// Return the new LHS for the assignment, Null = unlink
// Find selects
AstNode* newlhsp = nullptr; // nullptr = unlink old assign
AstSel* bitselp = nullptr;
const AstSel* bitselp = nullptr;
AstArraySel* arrayselp = nullptr;
if (VN_IS(lhsp, Sel)) {
bitselp = VN_CAST(lhsp, Sel);
arrayselp = VN_CAST(bitselp->fromp(), ArraySel);
bitselp = VN_AS(lhsp, Sel);
arrayselp = VN_AS(bitselp->fromp(), ArraySel);
} else {
arrayselp = VN_CAST(lhsp, ArraySel);
arrayselp = VN_AS(lhsp, ArraySel);
}
UASSERT_OBJ(arrayselp, nodep, "No arraysel under bitsel?");
UASSERT_OBJ(!VN_IS(arrayselp->dtypep()->skipRefp(), UnpackArrayDType), nodep,
@ -219,28 +220,28 @@ private:
//=== Dimensions: __Vdlyvdim__
std::deque<AstNode*> dimvalp; // Assignment value for each dimension of assignment
AstNode* dimselp = arrayselp;
for (; VN_IS(dimselp, ArraySel); dimselp = VN_CAST(dimselp, ArraySel)->fromp()) {
AstNode* valp = VN_CAST(dimselp, ArraySel)->bitp()->unlinkFrBack();
for (; VN_IS(dimselp, ArraySel); dimselp = VN_AS(dimselp, ArraySel)->fromp()) {
AstNode* const valp = VN_AS(dimselp, ArraySel)->bitp()->unlinkFrBack();
dimvalp.push_front(valp);
}
AstVarRef* varrefp = VN_CAST(dimselp, VarRef);
AstVarRef* const varrefp = VN_AS(dimselp, VarRef);
UASSERT_OBJ(varrefp, nodep, "No var underneath arraysels");
UASSERT_OBJ(varrefp->varScopep(), varrefp, "Var didn't get varscoped in V3Scope.cpp");
varrefp->unlinkFrBack();
AstVar* oldvarp = varrefp->varp();
const AstVar* const oldvarp = varrefp->varp();
const int modVecNum = m_scopeVecMap[varrefp->varScopep()]++;
//
std::deque<AstNode*> dimreadps; // Read value for each dimension of assignment
for (unsigned dimension = 0; dimension < dimvalp.size(); dimension++) {
AstNode* dimp = dimvalp[dimension];
AstNode* const dimp = dimvalp[dimension];
if (VN_IS(dimp, Const)) { // bit = const, can just use it
dimreadps.push_front(dimp);
} else {
const string bitvarname = (string("__Vdlyvdim") + cvtToStr(dimension) + "__"
+ oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
AstVarScope* bitvscp
AstVarScope* const bitvscp
= createVarSc(varrefp->varScopep(), bitvarname, dimp->width(), nullptr);
AstAssign* bitassignp = new AstAssign(
AstAssign* const bitassignp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, VAccess::WRITE),
dimp);
nodep->addNextHere(bitassignp);
@ -251,16 +252,16 @@ private:
//=== Bitselect: __Vdlyvlsb__
AstNode* bitreadp = nullptr; // Code to read Vdlyvlsb
if (bitselp) {
AstNode* lsbvaluep = bitselp->lsbp()->unlinkFrBack();
AstNode* const lsbvaluep = bitselp->lsbp()->unlinkFrBack();
if (VN_IS(bitselp->fromp(), Const)) {
// vlsb = constant, can just push constant into where we use it
bitreadp = lsbvaluep;
} else {
const string bitvarname = (string("__Vdlyvlsb__") + oldvarp->shortName() + "__v"
+ cvtToStr(modVecNum));
AstVarScope* bitvscp
AstVarScope* const bitvscp
= createVarSc(varrefp->varScopep(), bitvarname, lsbvaluep->width(), nullptr);
AstAssign* bitassignp = new AstAssign(
AstAssign* const bitassignp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, VAccess::WRITE),
lsbvaluep);
nodep->addNextHere(bitassignp);
@ -274,9 +275,9 @@ private:
// vval = constant, can just push constant into where we use it
valreadp = nodep->rhsp()->unlinkFrBack();
} else {
string valvarname
const string valvarname
= (string("__Vdlyvval__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
AstVarScope* valvscp
AstVarScope* const valvscp
= createVarSc(varrefp->varScopep(), valvarname, 0, nodep->rhsp()->dtypep());
newlhsp = new AstVarRef(nodep->fileline(), valvscp, VAccess::WRITE);
valreadp = new AstVarRef(nodep->fileline(), valvscp, VAccess::READ);
@ -291,16 +292,16 @@ private:
// then we told this nodep->user3 we can use its Vdlyvset rather than making a new one.
// This is good for code like:
// for (i=0; i<5; i++) vector[i] <= something;
setvscp = VN_CAST(nodep->user3p(), VarScope);
setvscp = VN_AS(nodep->user3p(), VarScope);
++m_statSharedSet;
} else { // Create new one
string setvarname
const string setvarname
= (string("__Vdlyvset__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
setvscp = createVarSc(varrefp->varScopep(), setvarname, 1, nullptr);
setinitp = new AstAssignPre(nodep->fileline(),
new AstVarRef(nodep->fileline(), setvscp, VAccess::WRITE),
new AstConst(nodep->fileline(), 0));
AstAssign* setassignp = new AstAssign(
AstAssign* const setassignp = new AstAssign(
nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, VAccess::WRITE),
new AstConst(nodep->fileline(), AstConst::BitTrue()));
nodep->addNextHere(setassignp);
@ -325,15 +326,15 @@ private:
// Build "IF (changeit) ...
UINFO(9, " For " << setvscp << endl);
UINFO(9, " & " << varrefp << endl);
AstAlwaysPost* finalp = VN_CAST(varrefp->varScopep()->user4p(), AlwaysPost);
AstAlwaysPost* finalp = VN_AS(varrefp->varScopep()->user4p(), AlwaysPost);
if (finalp) {
AstActive* oldactivep = VN_CAST(finalp->user2p(), Active);
AstActive* const oldactivep = VN_AS(finalp->user2p(), Active);
checkActivePost(varrefp, oldactivep);
if (setinitp) oldactivep->addStmtsp(setinitp);
} else { // first time we've dealt with this memory
finalp = new AstAlwaysPost(nodep->fileline(), nullptr /*sens*/, nullptr /*body*/);
UINFO(9, " Created " << finalp << endl);
AstActive* newactp = createActivePost(varrefp);
AstActive* const newactp = createActivePost(varrefp);
newactp->addStmtsp(finalp);
varrefp->varScopep()->user4p(finalp);
finalp->user2p(newactp);
@ -343,7 +344,7 @@ private:
if (finalp->user3p() == setvscp) {
// Optimize as above; if sharing Vdlyvset *ON SAME VARIABLE*,
// we can share the IF statement too
postLogicp = VN_CAST(finalp->user4p(), If);
postLogicp = VN_AS(finalp->user4p(), If);
UASSERT_OBJ(postLogicp, nodep,
"Delayed assignment misoptimized; prev var found w/o associated IF");
} else {
@ -397,14 +398,14 @@ private:
}
if (VN_IS(nodep->lhsp(), ArraySel)
|| (VN_IS(nodep->lhsp(), Sel)
&& VN_IS(VN_CAST(nodep->lhsp(), Sel)->fromp(), ArraySel))) {
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
AstNode* newlhsp = createDlyArray(nodep, lhsp);
&& VN_IS(VN_AS(nodep->lhsp(), Sel)->fromp(), ArraySel))) {
AstNode* const lhsp = nodep->lhsp()->unlinkFrBack();
AstNode* const newlhsp = createDlyArray(nodep, lhsp);
if (m_inLoop) {
nodep->v3warn(BLKLOOPINIT, "Unsupported: Delayed assignment to array inside for "
"loops (non-delayed is ok - see docs)");
}
AstBasicDType* basicp = lhsp->dtypep()->basicp();
const AstBasicDType* const basicp = lhsp->dtypep()->basicp();
if (basicp && basicp->isEventValue()) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: event arrays");
}
@ -432,18 +433,18 @@ private:
nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should "
"have converted in V3Active");
}
AstVarScope* oldvscp = nodep->varScopep();
AstVarScope* const oldvscp = nodep->varScopep();
UASSERT_OBJ(oldvscp, nodep, "Var didn't get varscoped in V3Scope.cpp");
AstVarScope* dlyvscp = VN_CAST(oldvscp->user1p(), VarScope);
AstVarScope* dlyvscp = VN_AS(oldvscp->user1p(), VarScope);
if (dlyvscp) { // Multiple use of delayed variable
AstActive* oldactivep = VN_CAST(dlyvscp->user2p(), Active);
AstActive* const oldactivep = VN_AS(dlyvscp->user2p(), Active);
checkActivePost(nodep, oldactivep);
}
if (!dlyvscp) { // First use of this delayed variable
const string newvarname = (string("__Vdly__") + nodep->varp()->shortName());
dlyvscp = createVarSc(oldvscp, newvarname, 0, nullptr);
AstNodeAssign* prep;
AstBasicDType* basicp = oldvscp->dtypep()->basicp();
const AstBasicDType* const basicp = oldvscp->dtypep()->basicp();
if (basicp && basicp->isEventValue()) {
// Events go to zero on next timestep unless reactivated
prep = new AstAssignPre(
@ -456,19 +457,20 @@ private:
new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE),
new AstVarRef(nodep->fileline(), oldvscp, VAccess::READ));
}
AstNodeAssign* postp = new AstAssignPost(
AstNodeAssign* const postp = new AstAssignPost(
nodep->fileline(),
new AstVarRef(nodep->fileline(), oldvscp, VAccess::WRITE),
new AstVarRef(nodep->fileline(), dlyvscp, VAccess::READ));
postp->lhsp()->user2(true); // Don't detect this assignment
oldvscp->user1p(dlyvscp); // So we can find it later
// Make new ACTIVE with identical sensitivity tree
AstActive* newactp = createActivePost(nodep);
AstActive* const newactp = createActivePost(nodep);
dlyvscp->user2p(newactp);
newactp->addStmtsp(prep); // Add to FRONT of statements
newactp->addStmtsp(postp);
}
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE);
AstVarRef* const newrefp
= new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE);
newrefp->user2(true); // No reason to do it again
nodep->replaceWith(newrefp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
@ -510,6 +512,6 @@ public:
void V3Delayed::delayedAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DelayedVisitor visitor{nodep}; } // Destruct before checking
{ DelayedVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("delayed", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -152,6 +152,6 @@ public:
void V3Depth::depthAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DepthVisitor visitor{nodep}; } // Destruct before checking
{ DepthVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("depth", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
}

View File

@ -37,8 +37,8 @@ private:
// NODE STATE
// STATE
AstNodeModule* m_modp = nullptr; // Current module
AstCFunc* m_cfuncp = nullptr; // Current function
const AstNodeModule* m_modp = nullptr; // Current module
const AstCFunc* m_cfuncp = nullptr; // Current function
int m_depth = 0; // How deep in an expression
int m_deepNum = 0; // How many functions made
@ -94,9 +94,9 @@ private:
if (m_depth > v3Global.opt.compLimitBlocks()
&& !VN_IS(nodep, NodeCCall)) { // Already done
UINFO(4, "DeepBlocks " << m_depth << " " << nodep << endl);
AstNode* backp = nodep->backp(); // Only for debug
const AstNode* const backp = nodep->backp(); // Only for debug
if (debug() >= 9) backp->dumpTree(cout, "- pre : ");
AstCFunc* funcp = createDeepFunc(nodep);
AstCFunc* const funcp = createDeepFunc(nodep);
iterate(funcp);
if (debug() >= 9) backp->dumpTree(cout, "- post: ");
if (debug() >= 9) funcp->dumpTree(cout, "- func: ");
@ -129,6 +129,6 @@ public:
void V3DepthBlock::depthBlockAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DepthBlockVisitor visitor{nodep}; } // Destruct before checking
{ DepthBlockVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("deepblock", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -39,7 +39,7 @@ private:
// NODE STATE
// Cleared entire netlist
// AstCFunc::user() // bool. Indicates processing completed
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// TYPES
using FuncMmap = std::multimap<std::string, AstCFunc*>;
@ -107,14 +107,14 @@ private:
// If multiple functions exist, we need to select the appropriate scope.
for (FuncMmap::iterator it = m_modFuncs.begin(); it != m_modFuncs.end(); ++it) {
const string name = it->first;
AstCFunc* topFuncp = it->second;
AstCFunc* const topFuncp = it->second;
auto nextIt1 = it;
++nextIt1;
bool moreOfSame1 = (nextIt1 != m_modFuncs.end() && nextIt1->first == name);
const bool moreOfSame1 = (nextIt1 != m_modFuncs.end() && nextIt1->first == name);
if (moreOfSame1) {
// Multiple functions under this name, need a wrapper function
UINFO(6, " Wrapping " << name << " multifuncs\n");
AstCFunc* newfuncp = topFuncp->cloneTree(false);
AstCFunc* const newfuncp = topFuncp->cloneTree(false);
if (newfuncp->initsp()) newfuncp->initsp()->unlinkFrBackWithNext()->deleteTree();
if (newfuncp->stmtsp()) newfuncp->stmtsp()->unlinkFrBackWithNext()->deleteTree();
if (newfuncp->finalsp()) newfuncp->finalsp()->unlinkFrBackWithNext()->deleteTree();
@ -125,7 +125,7 @@ private:
for (FuncMmap::iterator eachIt = it;
eachIt != m_modFuncs.end() && eachIt->first == name; ++eachIt) {
it = eachIt;
AstCFunc* funcp = eachIt->second;
AstCFunc* const funcp = eachIt->second;
auto nextIt2 = eachIt;
++nextIt2;
const bool moreOfSame
@ -138,21 +138,21 @@ private:
funcp->declPrivate(true);
AstNode* argsp = nullptr;
for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp = stmtp->nextp()) {
if (AstVar* portp = VN_CAST(stmtp, Var)) {
if (AstVar* const portp = VN_CAST(stmtp, Var)) {
if (portp->isIO() && !portp->isFuncReturn()) {
AstNode* newp = new AstVarRef(portp->fileline(), portp,
portp->isWritable() ? VAccess::WRITE
: VAccess::READ);
AstNode* const newp = new AstVarRef(
portp->fileline(), portp,
portp->isWritable() ? VAccess::WRITE : VAccess::READ);
argsp = argsp ? argsp->addNextNull(newp) : newp;
}
}
}
AstNode* returnp = new AstCReturn(
AstNode* const returnp = new AstCReturn(
funcp->fileline(), new AstCCall(funcp->fileline(), funcp, argsp));
if (moreOfSame) {
AstIf* ifp = new AstIf(
AstIf* const ifp = new AstIf(
funcp->fileline(),
new AstEq(
funcp->fileline(), new AstCMath(funcp->fileline(), "this", 64),
@ -289,6 +289,6 @@ public:
void V3Descope::descopeAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ DescopeVisitor visitor{nodep}; } // Destruct before checking
{ DescopeVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("descope", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -30,7 +30,7 @@ EmitCParentModule::EmitCParentModule() {
}
};
for (AstNode* modp = v3Global.rootp()->modulesp(); modp; modp = modp->nextp()) {
setAll(VN_CAST(modp, NodeModule));
setAll(VN_AS(modp, NodeModule));
}
setAll(v3Global.rootp()->constPoolp()->modp());
}
@ -57,7 +57,7 @@ string EmitCBaseVisitor::funcNameProtect(const AstCFunc* nodep, const AstNodeMod
}
AstCFile* EmitCBaseVisitor::newCFile(const string& filename, bool slow, bool source) {
AstCFile* cfilep = new AstCFile(v3Global.rootp()->fileline(), filename);
AstCFile* const cfilep = new AstCFile(v3Global.rootp()->fileline(), filename);
cfilep->slow(slow);
cfilep->source(source);
v3Global.rootp()->addFilesp(cfilep);
@ -78,7 +78,7 @@ string EmitCBaseVisitor::cFuncArgs(const AstCFunc* nodep) {
}
// Might be a user function with argument list.
for (const AstNode* stmtp = nodep->argsp(); stmtp; stmtp = stmtp->nextp()) {
if (const AstVar* portp = VN_CAST_CONST(stmtp, Var)) {
if (const AstVar* const portp = VN_CAST(stmtp, Var)) {
if (portp->isIO() && !portp->isFuncReturn()) {
if (args != "") args += ", ";
if (nodep->dpiImportPrototype() || nodep->dpiExportDispatcher()) {
@ -134,9 +134,8 @@ void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, bool asRef) {
const auto emitDeclArrayBrackets = [this](const AstVar* nodep) -> void {
// This isn't very robust and may need cleanup for other data types
for (const AstUnpackArrayDType* arrayp
= VN_CAST_CONST(nodep->dtypeSkipRefp(), UnpackArrayDType);
arrayp; arrayp = VN_CAST_CONST(arrayp->subDTypep()->skipRefp(), UnpackArrayDType)) {
for (const AstUnpackArrayDType* arrayp = VN_CAST(nodep->dtypeSkipRefp(), UnpackArrayDType);
arrayp; arrayp = VN_CAST(arrayp->subDTypep()->skipRefp(), UnpackArrayDType)) {
puts("[" + cvtToStr(arrayp->elementsConst()) + "]");
}
};
@ -221,7 +220,7 @@ void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, bool asRef) {
void EmitCBaseVisitor::emitModCUse(const AstNodeModule* modp, VUseType useType) {
string nl;
for (AstNode* itemp = modp->stmtsp(); itemp; itemp = itemp->nextp()) {
if (AstCUse* usep = VN_CAST(itemp, CUse)) {
if (AstCUse* const usep = VN_CAST(itemp, CUse)) {
if (usep->useType() == useType) {
if (usep->useType().isInclude()) {
puts("#include \"" + prefixNameProtect(usep) + ".h\"\n");
@ -239,7 +238,7 @@ void EmitCBaseVisitor::emitModCUse(const AstNodeModule* modp, VUseType useType)
void EmitCBaseVisitor::emitTextSection(const AstNodeModule* modp, AstType type) {
int last_line = -999;
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstNodeText* textp = VN_CAST(nodep, NodeText)) {
if (const AstNodeText* const textp = VN_CAST(nodep, NodeText)) {
if (nodep->type() == type) {
if (last_line != nodep->fileline()->lineno()) {
if (last_line < 0) {

View File

@ -34,14 +34,14 @@ class EmitCParentModule final {
// NODE STATE
// AstFunc::user4p() AstNodeModule* Parent module pointer
// AstVar::user4p() AstNodeModule* Parent module pointer
AstUser4InUse user4InUse;
const AstUser4InUse user4InUse;
public:
EmitCParentModule();
VL_UNCOPYABLE(EmitCParentModule);
static const AstNodeModule* get(const AstNode* nodep) {
return VN_CAST_CONST(nodep->user4p(), NodeModule);
return VN_AS(nodep->user4p(), NodeModule);
}
};

View File

@ -38,7 +38,7 @@ protected:
// VISITORS
virtual void visit(AstInitArray* nodep) override {
const AstUnpackArrayDType* const dtypep
= VN_CAST(nodep->dtypep()->skipRefp(), UnpackArrayDType);
= VN_AS(nodep->dtypep()->skipRefp(), UnpackArrayDType);
UASSERT_OBJ(dtypep, nodep, "Array initializer has non-array dtype");
const uint32_t size = dtypep->elementsConst();
const uint32_t elemBytes = dtypep->subDTypep()->widthTotalBytes();
@ -72,7 +72,7 @@ protected:
virtual void visit(AstConst* nodep) override {
const V3Number& num = nodep->num();
UASSERT_OBJ(!num.isFourState(), nodep, "4-state value in constant pool");
AstNodeDType* const dtypep = nodep->dtypep();
const AstNodeDType* const dtypep = nodep->dtypep();
if (num.isString()) {
// Note: putsQuoted does not track indentation, so we use this instead
puts("\"");

View File

@ -68,7 +68,7 @@ class EmitCConstPool final : public EmitCConstInit {
void emitVars(const AstConstPool* poolp) {
std::vector<const AstVar*> varps;
for (AstNode* nodep = poolp->modp()->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstVar* const varp = VN_CAST_CONST(nodep, Var)) { varps.push_back(varp); }
if (const AstVar* const varp = VN_CAST(nodep, Var)) { varps.push_back(varp); }
}
if (varps.empty()) return; // Constant pool is empty, so we are done

View File

@ -197,12 +197,12 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
} else {
// Format
bool isStmt = false;
if (const AstFScanF* dispp = VN_CAST(nodep, FScanF)) {
if (const AstFScanF* const dispp = VN_CAST(nodep, FScanF)) {
isStmt = false;
puts("VL_FSCANF_IX(");
iterate(dispp->filep());
puts(",");
} else if (const AstSScanF* dispp = VN_CAST(nodep, SScanF)) {
} else if (const AstSScanF* const dispp = VN_CAST(nodep, SScanF)) {
isStmt = false;
checkMaxWords(dispp->fromp());
puts("VL_SSCANF_I");
@ -212,7 +212,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
puts(",");
iterate(dispp->fromp());
puts(",");
} else if (const AstDisplay* dispp = VN_CAST(nodep, Display)) {
} else if (const AstDisplay* const dispp = VN_CAST(nodep, Display)) {
isStmt = true;
if (dispp->filep()) {
puts("VL_FWRITEF(");
@ -221,7 +221,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
} else {
puts("VL_WRITEF(");
}
} else if (const AstSFormat* dispp = VN_CAST(nodep, SFormat)) {
} else if (const AstSFormat* const dispp = VN_CAST(nodep, SFormat)) {
isStmt = true;
puts("VL_SFORMAT_X(");
puts(cvtToStr(dispp->lhsp()->widthMin()));
@ -238,7 +238,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
// Arguments
for (unsigned i = 0; i < emitDispState.m_argsp.size(); i++) {
const char fmt = emitDispState.m_argsChar[i];
AstNode* argp = emitDispState.m_argsp[i];
AstNode* const argp = emitDispState.m_argsp[i];
const string func = emitDispState.m_argsFunc[i];
if (func != "" || argp) {
puts(",");
@ -315,13 +315,14 @@ void EmitCFunc::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const
}
emitDispState.pushArg(fmtLetter, argp, "");
if (fmtLetter == 't' || fmtLetter == '^') {
AstSFormatF* fmtp = nullptr;
if (AstDisplay* nodep = VN_CAST(dispp, Display))
const AstSFormatF* fmtp = nullptr;
if (const AstDisplay* const nodep = VN_CAST(dispp, Display)) {
fmtp = nodep->fmtp();
else if (AstSFormat* nodep = VN_CAST(dispp, SFormat))
} else if (const AstSFormat* const nodep = VN_CAST(dispp, SFormat)) {
fmtp = nodep->fmtp();
else
} else {
fmtp = VN_CAST(dispp, SFormatF);
}
UASSERT_OBJ(fmtp, dispp,
"Use of %t must be under AstDisplay, AstSFormat, or AstSFormatF");
UASSERT_OBJ(!fmtp->timeunit().isNone(), fmtp, "timenunit must be set");
@ -472,7 +473,7 @@ void EmitCFunc::emitDereference(const string& pointer) {
}
void EmitCFunc::emitCvtPackStr(AstNode* nodep) {
if (const AstConst* constp = VN_CAST(nodep, Const)) {
if (const AstConst* const constp = VN_CAST(nodep, Const)) {
putbs("std::string(");
putsQuoted(constp->num().toString());
puts(")");
@ -533,13 +534,11 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string
puts(",");
if (!assigntop) {
puts(assignString);
} else if (VN_IS(assigntop, VarRef)) {
} else {
if (!assigntop->selfPointer().empty()) {
emitDereference(assigntop->selfPointerProtect(m_useSelfForThis));
}
puts(assigntop->varp()->nameProtect());
} else {
iterateAndNextNull(assigntop);
}
for (int word = VL_WORDS_I(upWidth) - 1; word >= 0; word--) {
// Only 32 bits - llx + long long here just to appease CPP format warning
@ -558,13 +557,11 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string
puts(",");
if (!assigntop) {
puts(assignString);
} else if (VN_IS(assigntop, VarRef)) {
} else {
if (!assigntop->selfPointer().empty()) {
emitDereference(assigntop->selfPointerProtect(m_useSelfForThis));
}
puts(assigntop->varp()->nameProtect());
} else {
iterateAndNextNull(assigntop);
}
for (int word = EMITC_NUM_CONSTW - 1; word >= 0; word--) {
// Only 32 bits - llx + long long here just to appease CPP format warning
@ -584,14 +581,14 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string
ofp()->printf("%.17e", nodep->num().toDouble());
}
} else if (nodep->isQuad()) {
vluint64_t num = nodep->toUQuad();
const vluint64_t num = nodep->toUQuad();
if (num < 10) {
ofp()->printf("%" VL_PRI64 "uULL", num);
} else {
ofp()->printf("0x%" VL_PRI64 "xULL", num);
}
} else {
uint32_t num = nodep->toUInt();
const uint32_t num = nodep->toUInt();
// Only 32 bits - llx + long long here just to appease CPP format warning
if (num < 10) {
puts(cvtToStr(num));
@ -624,20 +621,19 @@ void EmitCFunc::emitVarReset(AstVar* varp) {
// If a simple CONST value we initialize it using an enum
// If an ARRAYINIT we initialize it using an initial block similar to a signal
// puts("// parameter "+varp->nameProtect()+" = "+varp->valuep()->name()+"\n");
} else if (AstInitArray* initarp = VN_CAST(varp->valuep(), InitArray)) {
if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
} else if (const AstInitArray* const initarp = VN_CAST(varp->valuep(), InitArray)) {
if (AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
if (initarp->defaultp()) {
puts("for (int __Vi=0; __Vi<" + cvtToStr(adtypep->elementsConst()));
puts("; ++__Vi) {\n");
emitSetVarConstant(varNameProtected + "[__Vi]",
VN_CAST(initarp->defaultp(), Const));
emitSetVarConstant(varNameProtected + "[__Vi]", VN_AS(initarp->defaultp(), Const));
puts("}\n");
}
const AstInitArray::KeyItemMap& mapr = initarp->map();
for (const auto& itr : mapr) {
AstNode* valuep = itr.second->valuep();
AstNode* const valuep = itr.second->valuep();
emitSetVarConstant(varNameProtected + "[" + cvtToStr(itr.first) + "]",
VN_CAST(valuep, Const));
VN_AS(valuep, Const));
}
} else {
varp->v3fatalSrc("InitArray under non-arrayed var");
@ -650,26 +646,26 @@ void EmitCFunc::emitVarReset(AstVar* varp) {
string EmitCFunc::emitVarResetRecurse(const AstVar* varp, const string& varNameProtected,
AstNodeDType* dtypep, int depth, const string& suffix) {
dtypep = dtypep->skipRefp();
AstBasicDType* basicp = dtypep->basicp();
AstBasicDType* const basicp = dtypep->basicp();
// Returns string to do resetting, empty to do nothing (which caller should handle)
if (AstAssocArrayDType* adtypep = VN_CAST(dtypep, AssocArrayDType)) {
if (AstAssocArrayDType* const adtypep = VN_CAST(dtypep, AssocArrayDType)) {
// Access std::array as C array
const string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : "");
return emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), depth + 1,
suffix + ".atDefault()" + cvtarray);
} else if (VN_IS(dtypep, ClassRefDType)) {
return ""; // Constructor does it
} else if (AstDynArrayDType* adtypep = VN_CAST(dtypep, DynArrayDType)) {
} else if (const AstDynArrayDType* const adtypep = VN_CAST(dtypep, DynArrayDType)) {
// Access std::array as C array
const string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : "");
return emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), depth + 1,
suffix + ".atDefault()" + cvtarray);
} else if (AstQueueDType* adtypep = VN_CAST(dtypep, QueueDType)) {
} else if (const AstQueueDType* const adtypep = VN_CAST(dtypep, QueueDType)) {
// Access std::array as C array
const string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : "");
return emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), depth + 1,
suffix + ".atDefault()" + cvtarray);
} else if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
} else if (const AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
UASSERT_OBJ(adtypep->hi() >= adtypep->lo(), varp,
"Should have swapped msb & lsb earlier.");
const string ivar = string("__Vi") + cvtToStr(depth);
@ -683,8 +679,8 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, const string& varNameP
// String's constructor deals with it
return "";
} else if (basicp) {
bool zeroit
= (varp->attrFileDescr() // Zero so we don't core dump if never $fopen
const bool zeroit
= (varp->attrFileDescr() // Zero so we don't do file IO if never $fopen
|| (basicp && basicp->isZeroInit())
|| (v3Global.opt.underlineZero() && !varp->name().empty() && varp->name()[0] == '_')
|| (v3Global.opt.xInitial() == "fast" || v3Global.opt.xInitial() == "0"));
@ -692,7 +688,7 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, const string& varNameP
if (dtypep->isWide()) { // Handle unpacked; not basicp->isWide
string out;
if (varp->valuep()) {
AstConst* const constp = VN_CAST(varp->valuep(), Const);
const AstConst* const constp = VN_AS(varp->valuep(), Const);
if (!constp) varp->v3fatalSrc("non-const initializer for variable");
for (int w = 0; w < varp->widthWords(); ++w) {
out += varNameProtected + suffix + "[" + cvtToStr(w) + "] = ";
@ -737,8 +733,8 @@ void EmitCFunc::doubleOrDetect(AstChangeDet* changep, bool& gotOne) {
}
iterateAndNextNull(changep->lhsp());
} else {
AstNode* lhsp = changep->lhsp();
AstNode* rhsp = changep->rhsp();
AstNode* const lhsp = changep->lhsp();
AstNode* const rhsp = changep->rhsp();
UASSERT_OBJ(VN_IS(lhsp, VarRef) || VN_IS(lhsp, ArraySel), changep, "Not ref?");
UASSERT_OBJ(VN_IS(rhsp, VarRef) || VN_IS(rhsp, ArraySel), changep, "Not ref?");
for (int word = 0; word < (changep->lhsp()->isWide() ? changep->lhsp()->widthWords() : 1);
@ -792,7 +788,7 @@ void EmitCFunc::emitChangeDet() {
doubleOrDetect(nodep, gotOneIgnore);
string varname;
if (VN_IS(nodep->lhsp(), VarRef)) {
varname = ": " + VN_CAST(nodep->lhsp(), VarRef)->varp()->prettyName();
varname = ": " + VN_AS(nodep->lhsp(), VarRef)->varp()->prettyName();
}
puts(")) VL_DBG_MSGF(\" CHANGE: ");
puts(protect(nodep->fileline()->filename()));

View File

@ -37,7 +37,7 @@ constexpr int EMITC_NUM_CONSTW = 8;
class EmitCLazyDecls final : public AstNVisitor {
// NODE STATE/TYPES
// AstNode::user2() -> bool. Already emitted decl for symbols.
AstUser2InUse m_inuser2;
const AstUser2InUse m_inuser2;
// MEMBERS
std::unordered_set<string> m_emittedManually; // Set of names already declared manually.
@ -126,7 +126,7 @@ protected:
EmitCLazyDecls m_lazyDecls; // Visitor for emitting lazy declarations
bool m_useSelfForThis = false; // Replace "this" with "vlSelf"
const AstNodeModule* m_modp = nullptr; // Current module being emitted
AstCFunc* m_cfuncp = nullptr; // Current function being emitted
const AstCFunc* m_cfuncp = nullptr; // Current function being emitted
public:
// METHODS
@ -229,7 +229,7 @@ public:
puts(nodep->nameProtect() + "\\n\"); );\n");
for (AstNode* subnodep = nodep->argsp(); subnodep; subnodep = subnodep->nextp()) {
if (AstVar* varp = VN_CAST(subnodep, Var)) {
if (AstVar* const varp = VN_CAST(subnodep, Var)) {
if (varp->isFuncReturn()) emitVarDecl(varp);
}
}
@ -265,20 +265,21 @@ public:
virtual void visit(AstNodeAssign* nodep) override {
bool paren = true;
bool decind = false;
if (AstSel* selp = VN_CAST(nodep->lhsp(), Sel)) {
bool rhs = true;
if (AstSel* const selp = VN_CAST(nodep->lhsp(), Sel)) {
if (selp->widthMin() == 1) {
putbs("VL_ASSIGNBIT_");
emitIQW(selp->fromp());
if (nodep->rhsp()->isAllOnesV()) {
puts("O(");
rhs = false;
} else {
puts("I(");
}
puts(cvtToStr(nodep->widthMin()) + ",");
iterateAndNextNull(selp->lsbp());
puts(", ");
iterateAndNextNull(selp->fromp());
puts(", ");
if (rhs) puts(", ");
} else {
putbs("VL_ASSIGNSEL_");
emitIQW(selp->fromp());
@ -292,7 +293,7 @@ public:
iterateAndNextNull(selp->fromp());
puts(", ");
}
} else if (AstGetcRefN* selp = VN_CAST(nodep->lhsp(), GetcRefN)) {
} else if (const AstGetcRefN* const selp = VN_CAST(nodep->lhsp(), GetcRefN)) {
iterateAndNextNull(selp->lhsp());
puts(" = ");
putbs("VL_PUTC_N(");
@ -300,7 +301,7 @@ public:
puts(", ");
iterateAndNextNull(selp->rhsp());
puts(", ");
} else if (AstVar* varp = AstVar::scVarRecurse(nodep->lhsp())) {
} else if (AstVar* const varp = AstVar::scVarRecurse(nodep->lhsp())) {
putbs("VL_ASSIGN_"); // Set a systemC variable
emitScIQW(varp);
emitIQW(nodep);
@ -308,7 +309,7 @@ public:
puts(cvtToStr(nodep->widthMin()) + ",");
iterateAndNextNull(nodep->lhsp());
puts(", ");
} else if (AstVar* varp = AstVar::scVarRecurse(nodep->rhsp())) {
} else if (AstVar* const varp = AstVar::scVarRecurse(nodep->rhsp())) {
putbs("VL_ASSIGN_"); // Get a systemC variable
emitIQW(nodep);
emitScIQW(varp);
@ -323,7 +324,7 @@ public:
&& !VN_IS(nodep->rhsp(), AssocSel) //
&& !VN_IS(nodep->rhsp(), ArraySel)) {
// Wide functions assign into the array directly, don't need separate assign statement
m_wideTempRefp = VN_CAST(nodep->lhsp(), VarRef);
m_wideTempRefp = VN_AS(nodep->lhsp(), VarRef);
paren = false;
} else if (nodep->isWide()) {
putbs("VL_ASSIGN_W(");
@ -339,7 +340,7 @@ public:
if (!VN_IS(nodep->rhsp(), Const)) ofp()->putBreak();
puts("= ");
}
iterateAndNextNull(nodep->rhsp());
if (rhs) iterateAndNextNull(nodep->rhsp());
if (paren) puts(")");
if (decind) ofp()->blockDec();
puts(";\n");
@ -348,7 +349,7 @@ public:
virtual void visit(AstAssocSel* nodep) override {
iterateAndNextNull(nodep->fromp());
putbs(".at(");
AstAssocArrayDType* adtypep = VN_CAST(nodep->fromp()->dtypep(), AssocArrayDType);
AstAssocArrayDType* const adtypep = VN_AS(nodep->fromp()->dtypep(), AssocArrayDType);
UASSERT_OBJ(adtypep, nodep, "Associative select on non-associative type");
if (adtypep->keyDTypep()->isWide()) {
emitCvtWideArray(nodep->bitp(), nodep->fromp());
@ -429,11 +430,11 @@ public:
virtual void visit(AstWith* nodep) override {
// With uses a C++11 lambda
putbs("[=](");
if (auto* argrefp = nodep->indexArgRefp()) {
if (auto* const argrefp = nodep->indexArgRefp()) {
putbs(argrefp->dtypep()->cType(argrefp->nameProtect(), false, false));
puts(",");
}
if (auto* argrefp = nodep->valueArgRefp()) {
if (auto* const argrefp = nodep->valueArgRefp()) {
putbs(argrefp->dtypep()->cType(argrefp->nameProtect(), false, false));
}
// Probably fragile, V3Task may need to convert to a AstCReturn
@ -632,12 +633,12 @@ public:
puts(cvtToStr(nodep->memp()->dtypep()->subDTypep()->widthMin()));
uint32_t array_lo = 0;
{
const AstVarRef* varrefp = VN_CAST(nodep->memp(), VarRef);
const AstVarRef* const varrefp = VN_CAST(nodep->memp(), VarRef);
if (!varrefp) {
nodep->v3error(nodep->verilogKwd() << " loading non-variable");
} else if (VN_IS(varrefp->varp()->dtypeSkipRefp(), AssocArrayDType)) {
// nodep->memp() below will when verilated code is compiled create a C++ template
} else if (const AstUnpackArrayDType* adtypep
} else if (const AstUnpackArrayDType* const adtypep
= VN_CAST(varrefp->varp()->dtypeSkipRefp(), UnpackArrayDType)) {
putbs(", ");
puts(cvtToStr(varrefp->varp()->dtypep()->arrayUnpackedElements()));
@ -716,11 +717,11 @@ public:
uint32_t array_lo = 0;
uint32_t array_size = 0;
{
const AstVarRef* varrefp = VN_CAST(nodep->memp(), VarRef);
const AstVarRef* const varrefp = VN_CAST(nodep->memp(), VarRef);
if (!varrefp) {
nodep->v3error(nodep->verilogKwd() << " loading non-variable");
} else if (VN_CAST(varrefp->varp()->dtypeSkipRefp(), BasicDType)) {
} else if (const AstUnpackArrayDType* adtypep
} else if (const AstUnpackArrayDType* const adtypep
= VN_CAST(varrefp->varp()->dtypeSkipRefp(), UnpackArrayDType)) {
array_lo = adtypep->lo();
array_size = adtypep->elementsConst();
@ -898,7 +899,7 @@ public:
}
}
virtual void visit(AstTextBlock* nodep) override {
visit(VN_CAST(nodep, NodeSimpleText));
visit(static_cast<AstNodeSimpleText*>(nodep));
for (AstNode* childp = nodep->nodesp(); childp; childp = childp->nextp()) {
iterate(childp);
if (nodep->commas() && childp->nextp()) puts(", ");
@ -978,9 +979,9 @@ public:
}
virtual void visit(AstRedXor* nodep) override {
if (nodep->lhsp()->isWide()) {
visit(VN_CAST(nodep, NodeUniop));
visit(static_cast<AstNodeUniop*>(nodep));
} else {
AstVarRef* const vrefp = VN_CAST(nodep->lhsp(), VarRef);
const AstVarRef* const vrefp = VN_CAST(nodep->lhsp(), VarRef);
const int widthPow2 = vrefp ? vrefp->varp()->dtypep()->widthPow2()
: nodep->lhsp()->dtypep()->widthPow2();
UASSERT_OBJ(widthPow2 > 1, nodep,
@ -1042,16 +1043,14 @@ public:
}
virtual void visit(AstReplicate* nodep) override {
if (nodep->lhsp()->widthMin() == 1 && !nodep->isWide()) {
UASSERT_OBJ((static_cast<int>(VN_CAST(nodep->rhsp(), Const)->toUInt())
UASSERT_OBJ((static_cast<int>(VN_AS(nodep->rhsp(), Const)->toUInt())
* nodep->lhsp()->widthMin())
== nodep->widthMin(),
nodep, "Replicate non-constant or width miscomputed");
puts("VL_REPLICATE_");
emitIQW(nodep);
puts("OI(");
puts(cvtToStr(nodep->widthMin()));
if (nodep->lhsp()) puts("," + cvtToStr(nodep->lhsp()->widthMin()));
if (nodep->rhsp()) puts("," + cvtToStr(nodep->rhsp()->widthMin()));
if (nodep->lhsp()) puts(cvtToStr(nodep->lhsp()->widthMin()));
puts(",");
iterateAndNextNull(nodep->lhsp());
puts(", ");
@ -1064,26 +1063,24 @@ public:
virtual void visit(AstStreamL* nodep) override {
// Attempt to use a "fast" stream function for slice size = power of 2
if (!nodep->isWide()) {
uint32_t isPow2 = VN_CAST(nodep->rhsp(), Const)->num().countOnes() == 1;
uint32_t sliceSize = VN_CAST(nodep->rhsp(), Const)->toUInt();
const uint32_t isPow2 = VN_AS(nodep->rhsp(), Const)->num().countOnes() == 1;
const uint32_t sliceSize = VN_AS(nodep->rhsp(), Const)->toUInt();
if (isPow2 && sliceSize <= (nodep->isQuad() ? sizeof(uint64_t) : sizeof(uint32_t))) {
puts("VL_STREAML_FAST_");
emitIQW(nodep);
emitIQW(nodep->lhsp());
puts("I(");
puts(cvtToStr(nodep->widthMin()));
puts("," + cvtToStr(nodep->lhsp()->widthMin()));
puts("," + cvtToStr(nodep->rhsp()->widthMin()));
puts(",");
puts(cvtToStr(nodep->lhsp()->widthMin()));
puts(", ");
iterateAndNextNull(nodep->lhsp());
puts(", ");
uint32_t rd_log2 = V3Number::log2b(VN_CAST(nodep->rhsp(), Const)->toUInt());
const uint32_t rd_log2 = V3Number::log2b(VN_AS(nodep->rhsp(), Const)->toUInt());
puts(cvtToStr(rd_log2) + ")");
return;
}
}
emitOpName(nodep, "VL_STREAML_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)", nodep->lhsp(),
nodep->rhsp(), nullptr);
emitOpName(nodep, "VL_STREAML_%nq%lq%rq(%lw, %P, %li, %ri)", nodep->lhsp(), nodep->rhsp(),
nullptr);
}
virtual void visit(AstCastDynamic* nodep) override {
putbs("VL_CAST_DYNAMIC(");
@ -1133,7 +1130,7 @@ public:
}
virtual void visit(AstAddrOfCFunc* nodep) override {
// Note: Can be thought to handle more, but this is all that is needed right now
AstCFunc* const funcp = nodep->funcp();
const AstCFunc* const funcp = nodep->funcp();
UASSERT_OBJ(funcp->isLoose(), nodep, "Cannot take address of non-loose method");
puts("&");
puts(funcNameProtect(funcp));
@ -1205,7 +1202,7 @@ public:
}
}
virtual void visit(AstCReset* nodep) override {
AstVar* varp = nodep->varrefp()->varp();
AstVar* const varp = nodep->varrefp()->varp();
emitVarReset(varp);
}
virtual void visit(AstExecGraph* nodep) override {

View File

@ -40,7 +40,7 @@ class EmitCHeader final : public EmitCConstInit {
void emitCellDecls(const AstNodeModule* modp) {
bool first = true;
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstCell* const cellp = VN_CAST_CONST(nodep, Cell)) {
if (const AstCell* const cellp = VN_CAST(nodep, Cell)) {
decorateFirst(first, "// CELLS\n");
puts(prefixNameProtect(cellp->modp()) + "* " + cellp->nameProtect() + ";\n");
}
@ -102,7 +102,7 @@ class EmitCHeader final : public EmitCConstInit {
// Emit variables in consecutive anon and non-anon batches
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstVar* const varp = VN_CAST_CONST(nodep, Var)) {
if (const AstVar* const varp = VN_CAST(nodep, Var)) {
if (varp->isIO() || varp->isSignal() || varp->isClassMember() || varp->isTemp()) {
const bool anon = isAnonOk(varp);
if (anon != lastAnon) emitCurrentList();
@ -179,7 +179,7 @@ class EmitCHeader final : public EmitCConstInit {
void emitEnums(const AstNodeModule* modp) {
bool first = true;
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
const AstTypedef* const tdefp = VN_CAST_CONST(nodep, Typedef);
const AstTypedef* const tdefp = VN_CAST(nodep, Typedef);
if (!tdefp) continue;
if (!tdefp->attrPublic()) continue;
const AstEnumDType* const edtypep
@ -191,7 +191,7 @@ class EmitCHeader final : public EmitCConstInit {
} else {
puts("enum " + tdefp->name() + " {\n");
for (const AstEnumItem* itemp = edtypep->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), EnumItem)) {
itemp = VN_AS(itemp->nextp(), EnumItem)) {
puts(itemp->nameProtect());
puts(" = ");
iterate(itemp->valuep());
@ -206,7 +206,7 @@ class EmitCHeader final : public EmitCConstInit {
std::vector<const AstCFunc*> funcsp;
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstCFunc* const funcp = VN_CAST_CONST(nodep, CFunc)) {
if (const AstCFunc* const funcp = VN_CAST(nodep, CFunc)) {
if (funcp->dpiImportPrototype()) // Declared in __Dpi.h
continue;
if (funcp->dpiExportDispatcher()) // Declared in __Dpi.h
@ -230,7 +230,7 @@ class EmitCHeader final : public EmitCConstInit {
}
void emitAll(const AstNodeModule* modp) {
// Include files required by this AstNodeModule
if (const AstClass* const classp = VN_CAST_CONST(modp, Class)) {
if (const AstClass* const classp = VN_CAST(modp, Class)) {
if (classp->extendsp())
puts("#include \""
+ prefixNameProtect(classp->extendsp()->classp()->classOrPackagep())
@ -246,7 +246,7 @@ class EmitCHeader final : public EmitCConstInit {
emitTextSection(modp, AstType::atScHdr);
// Open class body {{{
if (const AstClass* const classp = VN_CAST_CONST(modp, Class)) {
if (const AstClass* const classp = VN_CAST(modp, Class)) {
puts("class ");
puts(prefixNameProtect(modp));
if (classp->extendsp()) {
@ -310,7 +310,7 @@ class EmitCHeader final : public EmitCConstInit {
emitAll(modp);
if (const AstClassPackage* const packagep = VN_CAST_CONST(modp, ClassPackage)) {
if (const AstClassPackage* const packagep = VN_CAST(modp, ClassPackage)) {
// Put the non-static class implementation in same h file for speed
emitAll(packagep->classp());
}
@ -335,6 +335,6 @@ void V3EmitC::emitcHeaders() {
// Process each module in turn
for (const AstNode* nodep = v3Global.rootp()->modulesp(); nodep; nodep = nodep->nextp()) {
if (VN_IS(nodep, Class)) continue; // Declared with the ClassPackage
EmitCHeader::main(VN_CAST_CONST(nodep, NodeModule));
EmitCHeader::main(VN_AS(nodep, NodeModule));
}
}

View File

@ -38,14 +38,14 @@ class EmitCGatherDependencies final : AstNVisitor {
// METHODS
void addSymsDependency() { m_dependencies.insert(EmitCBaseVisitor::symClassName()); }
void addModDependency(const AstNodeModule* modp) {
if (const AstClass* const classp = VN_CAST_CONST(modp, Class)) {
if (const AstClass* const classp = VN_CAST(modp, Class)) {
m_dependencies.insert(EmitCBaseVisitor::prefixNameProtect(classp->classOrPackagep()));
} else {
m_dependencies.insert(EmitCBaseVisitor::prefixNameProtect(modp));
}
}
void addDTypeDependency(const AstNodeDType* nodep) {
if (const AstClassRefDType* const dtypep = VN_CAST_CONST(nodep, ClassRefDType)) {
if (const AstClassRefDType* const dtypep = VN_CAST(nodep, ClassRefDType)) {
m_dependencies.insert(
EmitCBaseVisitor::prefixNameProtect(dtypep->classp()->classOrPackagep()));
}
@ -135,7 +135,7 @@ class EmitCGatherDependencies final : AstNVisitor {
public:
static const std::set<std::string> gather(AstCFunc* cfuncp) {
EmitCGatherDependencies visitor{cfuncp};
const EmitCGatherDependencies visitor{cfuncp};
return std::move(visitor.m_dependencies);
}
};
@ -193,7 +193,7 @@ class EmitCImp final : EmitCFunc {
// Emit static variable definitions
const string modName = prefixNameProtect(modp);
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstVar* const varp = VN_CAST_CONST(nodep, Var)) {
if (const AstVar* const varp = VN_CAST(nodep, Var)) {
if (varp->isStatic()) {
puts(varp->vlArgType(true, false, false, modName));
puts(";\n");
@ -205,7 +205,7 @@ class EmitCImp final : EmitCFunc {
const string modName = prefixNameProtect(modp);
bool first = true;
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstVar* const varp = VN_CAST_CONST(nodep, Var)) {
if (const AstVar* const varp = VN_CAST(nodep, Var)) {
if (varp->isParam()) {
if (first) {
puts("\n");
@ -241,7 +241,7 @@ class EmitCImp final : EmitCFunc {
ofp()->indentInc();
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstVar* const varp = VN_CAST_CONST(nodep, Var)) {
if (const AstVar* const varp = VN_CAST(nodep, Var)) {
if (const AstBasicDType* const dtypep
= VN_CAST(varp->dtypeSkipRefp(), BasicDType)) {
if (dtypep->keyword().isMTaskState()) {
@ -348,7 +348,7 @@ class EmitCImp final : EmitCFunc {
// just looking for loading the wrong model
VHashSha256 hash;
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstVar* varp = VN_CAST(nodep, Var)) {
if (const AstVar* const varp = VN_CAST(nodep, Var)) {
hash.insert(varp->name());
hash.insert(varp->dtypep()->width());
}
@ -369,7 +369,7 @@ class EmitCImp final : EmitCFunc {
// Save all members
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstVar* varp = VN_CAST(nodep, Var)) {
if (const AstVar* const varp = VN_CAST(nodep, Var)) {
if (varp->isIO() && modp->isTop() && optSystemC()) {
// System C top I/O doesn't need loading, as the
// lower level subinst code does it.
@ -446,7 +446,7 @@ class EmitCImp final : EmitCFunc {
}
void emitCommonImp(const AstNodeModule* modp) {
const AstClass* const classp
= VN_IS(modp, ClassPackage) ? VN_CAST_CONST(modp, ClassPackage)->classp() : nullptr;
= VN_IS(modp, ClassPackage) ? VN_AS(modp, ClassPackage)->classp() : nullptr;
if (hasCommonImp(modp) || hasCommonImp(classp)) {
std::set<string> headers;
@ -486,7 +486,7 @@ class EmitCImp final : EmitCFunc {
};
gather(modp);
if (const AstClassPackage* const packagep = VN_CAST_CONST(modp, ClassPackage)) {
if (const AstClassPackage* const packagep = VN_CAST(modp, ClassPackage)) {
gather(packagep->classp());
}
@ -556,7 +556,7 @@ class EmitCTrace final : EmitCFunc {
// NODE STATE/TYPES
// Cleared on netlist
// AstNode::user1() -> int. Enum number
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// MEMBERS
const bool m_slow; // Making slow file
@ -576,7 +576,7 @@ class EmitCTrace final : EmitCFunc {
if (m_slow) filename += "__Slow";
filename += ".cpp";
AstCFile* cfilep = newCFile(filename, m_slow, true /*source*/);
AstCFile* const cfilep = newCFile(filename, m_slow, true /*source*/);
cfilep->support(true);
if (optSystemC()) {
@ -595,23 +595,23 @@ class EmitCTrace final : EmitCFunc {
}
bool emitTraceIsScBv(AstTraceInc* nodep) {
const AstVarRef* varrefp = VN_CAST(nodep->declp()->valuep(), VarRef);
const AstVarRef* const varrefp = VN_CAST(nodep->declp()->valuep(), VarRef);
if (!varrefp) return false;
AstVar* varp = varrefp->varp();
AstVar* const varp = varrefp->varp();
return varp->isSc() && varp->isScBv();
}
bool emitTraceIsScBigUint(AstTraceInc* nodep) {
const AstVarRef* varrefp = VN_CAST(nodep->declp()->valuep(), VarRef);
const AstVarRef* const varrefp = VN_CAST(nodep->declp()->valuep(), VarRef);
if (!varrefp) return false;
AstVar* varp = varrefp->varp();
AstVar* const varp = varrefp->varp();
return varp->isSc() && varp->isScBigUint();
}
bool emitTraceIsScUint(AstTraceInc* nodep) {
const AstVarRef* varrefp = VN_CAST(nodep->declp()->valuep(), VarRef);
const AstVarRef* const varrefp = VN_CAST(nodep->declp()->valuep(), VarRef);
if (!varrefp) return false;
AstVar* varp = varrefp->varp();
AstVar* const varp = varrefp->varp();
return varp->isSc() && varp->isScUint();
}
@ -714,7 +714,7 @@ class EmitCTrace final : EmitCFunc {
if (v3Global.opt.traceFormat().fst()) {
// 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* enump = VN_CAST(nodep->skipRefToEnump(), EnumDType)) {
if (AstEnumDType* const enump = VN_CAST(nodep->skipRefToEnump(), EnumDType)) {
int enumNum = enump->user1();
if (!enumNum) {
enumNum = ++m_enumNum;
@ -724,7 +724,7 @@ class EmitCTrace final : EmitCFunc {
puts("const char* " + protect("__VenumItemNames") + "[]\n");
puts("= {");
for (AstEnumItem* itemp = enump->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), EnumItem)) {
itemp = VN_AS(itemp->nextp(), EnumItem)) {
if (++nvals > 1) puts(", ");
putbs("\"" + itemp->prettyName() + "\"");
}
@ -733,8 +733,8 @@ class EmitCTrace final : EmitCFunc {
puts("const char* " + protect("__VenumItemValues") + "[]\n");
puts("= {");
for (AstEnumItem* itemp = enump->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), EnumItem)) {
AstConst* constp = VN_CAST(itemp->valuep(), Const);
itemp = VN_AS(itemp->nextp(), EnumItem)) {
AstConst* const constp = VN_AS(itemp->valuep(), Const);
if (++nvals > 1) puts(", ");
putbs("\"" + constp->num().displayed(nodep, "%0b") + "\"");
}
@ -785,7 +785,7 @@ class EmitCTrace final : EmitCFunc {
void emitTraceValue(AstTraceInc* nodep, int arrayindex) {
if (AstVarRef* const varrefp = VN_CAST(nodep->valuep(), VarRef)) {
AstVar* varp = varrefp->varp();
AstVar* const varp = varrefp->varp();
puts("(");
if (emitTraceIsScBigUint(nodep)) {
puts("(vluint32_t*)");
@ -882,12 +882,12 @@ public:
void V3EmitC::emitcImp() {
UINFO(2, __FUNCTION__ << ": " << endl);
// Make parent module pointers available.
EmitCParentModule emitCParentModule;
const EmitCParentModule emitCParentModule;
// 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_CAST_CONST(nodep, NodeModule);
const AstNodeModule* const modp = VN_AS(nodep, NodeModule);
EmitCImp::main(modp, /* slow: */ true);
EmitCImp::main(modp, /* slow: */ false);
}
@ -902,13 +902,13 @@ void V3EmitC::emitcImp() {
void V3EmitC::emitcFiles() {
UINFO(2, __FUNCTION__ << ": " << endl);
for (AstNodeFile* filep = v3Global.rootp()->filesp(); filep;
filep = VN_CAST(filep->nextp(), NodeFile)) {
AstCFile* cfilep = VN_CAST(filep, CFile);
filep = VN_AS(filep->nextp(), NodeFile)) {
AstCFile* const cfilep = VN_CAST(filep, CFile);
if (cfilep && cfilep->tblockp()) {
V3OutCFile of(cfilep->name());
of.puts("// DESCR"
"IPTION: Verilator generated C++\n");
EmitCFunc visitor(cfilep->tblockp(), &of, true);
const EmitCFunc visitor(cfilep->tblockp(), &of, true);
}
}
}

View File

@ -135,8 +135,8 @@ class CMakeEmitter final {
std::vector<string> support_slow;
std::vector<string> global;
for (AstNodeFile* nodep = v3Global.rootp()->filesp(); nodep;
nodep = VN_CAST(nodep->nextp(), NodeFile)) {
AstCFile* cfilep = VN_CAST(nodep, CFile);
nodep = VN_AS(nodep->nextp(), NodeFile)) {
const AstCFile* const cfilep = VN_CAST(nodep, CFile);
if (cfilep && cfilep->source()) {
if (cfilep->support()) {
if (cfilep->slow()) {
@ -178,8 +178,8 @@ class CMakeEmitter final {
if (v3Global.opt.mtasks()) {
global.emplace_back("${VERILATOR_ROOT}/include/verilated_threads.cpp");
}
if (!v3Global.opt.protectLib().empty()) {
global.emplace_back(v3Global.opt.makeDir() + "/" + v3Global.opt.protectLib() + ".cpp");
if (!v3Global.opt.libCreate().empty()) {
global.emplace_back(v3Global.opt.makeDir() + "/" + v3Global.opt.libCreate() + ".cpp");
}
*of << "# Global classes, need linked once per executable\n";
@ -199,7 +199,7 @@ class CMakeEmitter final {
*of << "# User .cpp files (from .cpp's on Verilator command line)\n";
cmake_set_raw(*of, name + "_USER_CLASSES", deslash(cmake_list(v3Global.opt.cppFiles())));
if (const V3HierBlockPlan* planp = v3Global.hierPlanp()) {
if (const V3HierBlockPlan* const planp = v3Global.hierPlanp()) {
*of << "# Verilate hierarchical blocks\n";
// Sorted hierarchical blocks in order of leaf-first.
const V3HierBlockPlan::HierVector& hierBlocks = planp->hierBlocksSorted();
@ -238,7 +238,7 @@ class CMakeEmitter final {
// with .so
<< ")\n";
}
*of << "\n# Verilate the top module that refers protect-lib wrappers of above\n";
*of << "\n# Verilate the top module that refers to lib-create wrappers of above\n";
*of << "verilate(${TOP_TARGET_NAME} PREFIX " << v3Global.opt.prefix() << " TOP_MODULE "
<< v3Global.rootp()->topModulep()->name() << " DIRECTORY "
<< deslash(v3Global.opt.makeDir()) << " SOURCES ";
@ -260,5 +260,5 @@ public:
void V3EmitCMake::emit() {
UINFO(2, __FUNCTION__ << ": " << endl);
CMakeEmitter emitter;
const CMakeEmitter emitter;
}

View File

@ -23,14 +23,31 @@
#include "V3UniqueNames.h"
#include <algorithm>
#include <functional>
#include <vector>
class EmitCModel final : public EmitCFunc {
// TYPES
using CFuncVector = std::vector<const AstCFunc*>;
// MEMBERS
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()) {
if (const AstCFunc* const funcp = VN_CAST(nodep, CFunc)) {
if (cb(funcp)) funcps.push_back(funcp);
}
}
stable_sort(funcps.begin(), funcps.end(),
[](const AstNode* ap, const AstNode* bp) { return ap->name() < bp->name(); });
return funcps;
}
void putSectionDelimiter(const string& name) {
puts("\n");
puts("//============================================================\n");
@ -90,7 +107,7 @@ class EmitCModel final : public EmitCFunc {
"// The application code writes and reads these signals to\n"
"// propagate new values into/out from the Verilated model.\n");
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstVar* const varp = VN_CAST_CONST(nodep, Var)) {
if (const AstVar* const varp = VN_CAST(nodep, Var)) {
if (varp->isPrimaryIO()) { //
emitVarDecl(varp, /* asRef: */ true);
}
@ -102,7 +119,7 @@ class EmitCModel final : public EmitCFunc {
"// Public to allow access to /* verilator public */ items.\n"
"// Otherwise the application code can consider these internals.\n");
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstCell* const cellp = VN_CAST_CONST(nodep, Cell)) {
if (const AstCell* const cellp = VN_CAST(nodep, Cell)) {
puts(prefixNameProtect(cellp->modp()) + "* const " + cellp->nameProtect() + ";\n");
}
}
@ -136,7 +153,7 @@ class EmitCModel final : public EmitCFunc {
puts("\n");
ofp()->putsPrivate(false); // public:
puts("// API METHODS\n");
string callEvalEndStep
const string callEvalEndStep
= (v3Global.needTraceDumper() && !optSystemC()) ? "eval_end_step(); " : "";
if (optSystemC()) {
ofp()->putsPrivate(true); ///< eval() is invoked by our sensitive() calls.
@ -187,22 +204,11 @@ class EmitCModel final : public EmitCFunc {
// Emit DPI export dispatcher declarations
{
std::vector<const AstCFunc*> funcps;
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstCFunc* funcp = VN_CAST(nodep, CFunc)) {
if (!funcp->dpiExportDispatcher()) continue;
funcps.push_back(funcp);
}
}
stable_sort(funcps.begin(), funcps.end(), [](const AstNode* ap, const AstNode* bp) {
return ap->name() < bp->name();
});
const CFuncVector funcps
= findFuncps([](const AstCFunc* nodep) { return nodep->dpiExportDispatcher(); });
if (!funcps.empty()) {
puts("\n/// DPI Export functions\n");
for (const AstCFunc* funcp : funcps) { emitCFuncDecl(funcp, modp); }
for (const AstCFunc* funcp : funcps) emitCFuncDecl(funcp, modp);
}
}
@ -237,7 +243,7 @@ class EmitCModel final : public EmitCFunc {
// Set up IO references
for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstVar* const varp = VN_CAST_CONST(nodep, Var)) {
if (const AstVar* const varp = VN_CAST(nodep, Var)) {
if (varp->isPrimaryIO()) {
const string protName = varp->nameProtect();
puts(" , " + protName + "{vlSymsp->TOP." + protName + "}\n");
@ -247,7 +253,7 @@ class EmitCModel final : public EmitCFunc {
// Setup cell pointers
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstCell* const cellp = VN_CAST_CONST(nodep, Cell)) {
if (const AstCell* const cellp = VN_CAST(nodep, Cell)) {
const string protName = cellp->nameProtect();
puts(" , " + protName + "{vlSymsp->TOP." + protName + "}\n");
}
@ -422,7 +428,7 @@ class EmitCModel final : public EmitCFunc {
+ "(vlSymsp);\n");
if (v3Global.opt.threads() == 1) {
uint32_t mtaskId = 0;
const uint32_t mtaskId = 0;
putsDecoration("// MTask " + cvtToStr(mtaskId) + " start\n");
puts("VL_DEBUG_IF(VL_DBG_MSGF(\"MTask" + cvtToStr(mtaskId) + " starting\\n\"););\n");
puts("Verilated::mtaskId(" + cvtToStr(mtaskId) + ");\n");
@ -515,12 +521,6 @@ class EmitCModel final : public EmitCFunc {
puts("}\n");
}
putSectionDelimiter("Invoke final blocks");
// ::final
puts("\nvoid " + topClassName() + "::final() {\n");
puts(topModNameProtected + "__" + protect("_final") + "(&(vlSymsp->TOP));\n");
puts("}\n");
putSectionDelimiter("Utilities");
// ::contextp
puts("\nVerilatedContext* " + topClassName() + "::contextp() const {\n");
@ -533,6 +533,12 @@ class EmitCModel final : public EmitCFunc {
puts(/**/ "return vlSymsp->name();\n");
puts("}\n");
}
putSectionDelimiter("Invoke final blocks");
// ::final
puts("\nVL_ATTR_COLD void " + topClassName() + "::final() {\n");
puts(/**/ topModNameProtected + "__" + protect("_final") + "(&(vlSymsp->TOP));\n");
puts("}\n");
}
void emitTraceMethods(AstNodeModule* modp) {
@ -546,7 +552,7 @@ class EmitCModel final : public EmitCFunc {
+ "* tracep);\n");
// Static helper function
puts("\nstatic void " + protect("trace_init") + "(void* voidSelf, "
puts("\nVL_ATTR_COLD static void " + protect("trace_init") + "(void* voidSelf, "
+ v3Global.opt.traceClassBase() + "* tracep, uint32_t code) {\n");
putsDecoration("// Callback from tracep->open()\n");
puts(voidSelfAssign(modp));
@ -564,16 +570,42 @@ class EmitCModel final : public EmitCFunc {
puts("}\n");
// Forward declaration
puts("\nvoid " + topModNameProtected + "__" + protect("trace_register") + "("
puts("\nVL_ATTR_COLD void " + topModNameProtected + "__" + protect("trace_register") + "("
+ topModNameProtected + "* vlSelf, " + v3Global.opt.traceClassBase()
+ "* tracep);\n");
const CFuncVector traceInitFuncps
= findFuncps([](const AstCFunc* nodep) { return nodep->dpiTraceInit(); });
for (const AstCFunc* const funcp : traceInitFuncps) emitCFuncDecl(funcp, modp);
// ::trace
puts("\nvoid " + topClassName() + "::trace(");
puts(v3Global.opt.traceClassBase() + "C* tfp, int, int) {\n");
puts("tfp->spTrace()->addInitCb(&" + protect("trace_init") + ", &(vlSymsp->TOP));\n");
puts(topModNameProtected + "__" + protect("trace_register")
puts("\nVL_ATTR_COLD void " + topClassName() + "::trace(");
puts(v3Global.opt.traceClassBase() + "C* tfp, int levels, int options) {\n");
puts(/**/ "if (false && levels && options) {} // Prevent unused\n");
puts(/**/ "tfp->spTrace()->addInitCb(&" + protect("trace_init") + ", &(vlSymsp->TOP));\n");
puts(/**/ topModNameProtected + "__" + protect("trace_register")
+ "(&(vlSymsp->TOP), tfp->spTrace());\n");
if (!traceInitFuncps.empty()) {
puts(/**/ "if (levels > 0) {\n");
puts(/****/ "const QData tfpq = reinterpret_cast<QData>(tfp);\n");
for (const AstCFunc* const funcp : traceInitFuncps) {
// 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_");
UASSERT_OBJ(handle.substr(0, wr_len) == "__Vdpiimwrap_", funcp,
"Strange trace_init_task function name");
handle = "vlSymsp->TOP." + handle.substr(wr_len);
const string::size_type pos = handle.rfind("__DOT__");
UASSERT_OBJ(pos != string::npos, funcp, "Strange trace_init_task function name");
handle = handle.substr(0, pos) + "__DOT__handle___05FV";
puts(funcNameProtect(funcp, modp) + "(" + handle
+ ", tfpq, levels - 1, options);\n");
}
puts(/**/ "}\n");
}
puts("}\n");
}
@ -582,16 +614,16 @@ class EmitCModel final : public EmitCFunc {
puts("\nVerilatedSerialize& operator<<(VerilatedSerialize& os, " + topClassName()
+ "& rhs) {\n");
puts("Verilated::quiesce();\n");
puts("rhs.vlSymsp->" + protect("__Vserialize") + "(os);\n");
puts("return os;\n");
puts(/**/ "Verilated::quiesce();\n");
puts(/**/ "rhs.vlSymsp->" + protect("__Vserialize") + "(os);\n");
puts(/**/ "return os;\n");
puts("}\n");
puts("\nVerilatedDeserialize& operator>>(VerilatedDeserialize& os, " + topClassName()
+ "& rhs) {\n");
puts("Verilated::quiesce();\n");
puts("rhs.vlSymsp->" + protect("__Vdeserialize") + "(os);\n");
puts("return os;\n");
puts(/**/ "Verilated::quiesce();\n");
puts(/**/ "rhs.vlSymsp->" + protect("__Vdeserialize") + "(os);\n");
puts(/**/ "return os;\n");
puts("}\n");
}

View File

@ -34,13 +34,13 @@ class EmitCSyms final : EmitCBaseVisitor {
// NODE STATE
// Cleared on Netlist
// AstNodeModule::user1() -> bool. Set true __Vconfigure called
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// TYPES
struct ScopeData {
string m_symName;
string m_prettyName;
int m_timeunit;
const string m_symName;
const string m_prettyName;
const int m_timeunit;
string m_type;
ScopeData(const string& symName, const string& prettyName, int timeunit,
const string& type)
@ -50,22 +50,22 @@ class EmitCSyms final : EmitCBaseVisitor {
, m_type{type} {}
};
struct ScopeFuncData {
AstScopeName* m_scopep;
AstCFunc* m_cfuncp;
AstNodeModule* m_modp;
AstScopeName* const m_scopep;
AstCFunc* const m_cfuncp;
AstNodeModule* const m_modp;
ScopeFuncData(AstScopeName* scopep, AstCFunc* funcp, AstNodeModule* modp)
: m_scopep{scopep}
, m_cfuncp{funcp}
, m_modp{modp} {}
};
struct ScopeVarData {
string m_scopeName;
string m_varBasePretty;
AstVar* m_varp;
AstNodeModule* m_modp;
AstScope* m_scopep;
const string m_scopeName;
const string m_varBasePretty;
AstVar* const m_varp;
const AstNodeModule* const m_modp;
AstScope* const m_scopep;
ScopeVarData(const string& scopeName, const string& varBasePretty, AstVar* varp,
AstNodeModule* modp, AstScope* scopep)
const AstNodeModule* modp, AstScope* scopep)
: m_scopeName{scopeName}
, m_varBasePretty{varBasePretty}
, m_varp{varp}
@ -104,7 +104,7 @@ class EmitCSyms final : EmitCBaseVisitor {
ScopeNames m_vpiScopeCandidates; // All scopes for VPI
ScopeNameHierarchy m_vpiScopeHierarchy; // The actual hierarchy of scopes
int m_coverBins = 0; // Coverage bin number
bool m_dpiHdrOnly; // Only emit the DPI header
const bool m_dpiHdrOnly; // Only emit the DPI header
int m_numStmts = 0; // Number of statements output
int m_funcNum = 0; // CFunc split function number
V3OutCFile* m_ofpBase = nullptr; // Base (not split) C file
@ -124,8 +124,8 @@ class EmitCSyms final : EmitCBaseVisitor {
// Prevent GCC compile time error; name check all things that reach C++ code
if (nodep->name() != ""
&& !(VN_IS(nodep, CFunc)
&& (VN_CAST(nodep, CFunc)->isConstructor()
|| VN_CAST(nodep, CFunc)->isDestructor()))) {
&& (VN_AS(nodep, CFunc)->isConstructor()
|| VN_AS(nodep, CFunc)->isDestructor()))) {
const string rsvd = V3LanguageWords::isKeyword(nodep->name());
if (rsvd != "") {
// Generally V3Name should find all of these and throw SYMRSVDWORD.
@ -193,12 +193,12 @@ class EmitCSyms final : EmitCBaseVisitor {
// Someday. For now public isn't common.
for (std::vector<ScopeModPair>::iterator itsc = m_scopes.begin(); itsc != m_scopes.end();
++itsc) {
AstScope* scopep = itsc->first;
AstNodeModule* smodp = itsc->second;
AstScope* const scopep = itsc->first;
const AstNodeModule* const smodp = itsc->second;
for (std::vector<ModVarPair>::iterator it = m_modVars.begin(); it != m_modVars.end();
++it) {
AstNodeModule* modp = it->first;
AstVar* varp = it->second;
const AstNodeModule* const modp = it->first;
AstVar* const varp = it->second;
if (modp == smodp) {
// Need to split the module + var name into the
// original-ish full scope and variable name under that scope.
@ -208,7 +208,7 @@ class EmitCSyms final : EmitCBaseVisitor {
string scpName;
string varBase;
if (whole.substr(0, 10) == "__DOT__TOP") whole.replace(0, 10, "");
string::size_type dpos = whole.rfind("__DOT__");
const string::size_type dpos = whole.rfind("__DOT__");
if (dpos != string::npos) {
scpName = whole.substr(0, dpos);
varBase = whole.substr(dpos + strlen("__DOT__"));
@ -245,7 +245,7 @@ class EmitCSyms final : EmitCBaseVisitor {
if (above.substr(0, 4) == "TOP.") above.replace(0, 4, "");
while (!above.empty()) {
string::size_type pos = above.rfind("__");
const string::size_type pos = above.rfind("__");
if (pos == string::npos) break;
above.resize(pos);
if (m_vpiScopeHierarchy.find(above) != m_vpiScopeHierarchy.end()) {
@ -402,7 +402,7 @@ void EmitCSyms::emitSymHdr() {
puts("\n// INCLUDE MODULE CLASSES\n");
for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep;
nodep = VN_CAST(nodep->nextp(), NodeModule)) {
nodep = VN_AS(nodep->nextp(), NodeModule)) {
if (VN_IS(nodep, Class)) continue; // Class included earlier
puts("#include \"" + prefixNameProtect(nodep) + ".h\"\n");
}
@ -411,7 +411,7 @@ void EmitCSyms::emitSymHdr() {
puts("\n// DPI TYPES for DPI Export callbacks (Internal use)\n");
std::map<const string, int> types; // Remove duplicates and sort
for (const auto& itr : m_scopeFuncs) {
AstCFunc* funcp = itr.second.m_cfuncp;
const AstCFunc* const funcp = itr.second.m_cfuncp;
if (funcp->dpiExportImpl()) {
const string cbtype
= protect(v3Global.opt.prefix() + "__Vcb_" + funcp->cname() + "_t");
@ -461,8 +461,8 @@ void EmitCSyms::emitSymHdr() {
puts("\n// MODULE INSTANCE STATE\n");
for (const auto& i : m_scopes) {
AstScope* scopep = i.first;
AstNodeModule* modp = i.second;
const AstScope* const scopep = i.first;
const AstNodeModule* const modp = i.second;
if (VN_IS(modp, Class)) continue;
const string name = prefixNameProtect(modp);
ofp()->printf("%-30s ", name.c_str());
@ -484,7 +484,8 @@ void EmitCSyms::emitSymHdr() {
for (const V3GraphVertex* vxp
= v3Global.rootp()->execGraphp()->depGraphp()->verticesBeginp();
vxp; vxp = vxp->verticesNextp()) {
ExecMTask* mtp = dynamic_cast<ExecMTask*>(const_cast<V3GraphVertex*>(vxp));
const ExecMTask* const mtp
= dynamic_cast<ExecMTask*>(const_cast<V3GraphVertex*>(vxp));
if (maxProfilerId < mtp->profilerId()) maxProfilerId = mtp->profilerId();
}
}
@ -551,9 +552,9 @@ void EmitCSyms::checkSplit(bool usesVfinal) {
v3Global.useParallelBuild(true);
m_numStmts = 0;
string filename
const string filename
= v3Global.opt.makeDir() + "/" + symClassName() + "__" + cvtToStr(++m_funcNum) + ".cpp";
AstCFile* cfilep = newCFile(filename, true /*slow*/, true /*source*/);
AstCFile* const cfilep = newCFile(filename, true /*slow*/, true /*source*/);
cfilep->support(true);
m_usesVfinal[m_funcNum] = usesVfinal;
closeSplit();
@ -584,7 +585,7 @@ void EmitCSyms::emitSymImpPreamble() {
puts("#include \"" + symClassName() + ".h\"\n");
puts("#include \"" + topClassName() + ".h\"\n");
for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep;
nodep = VN_CAST(nodep->nextp(), NodeModule)) {
nodep = VN_AS(nodep->nextp(), NodeModule)) {
if (VN_IS(nodep, Class)) continue; // Class included earlier
puts("#include \"" + prefixNameProtect(nodep) + ".h\"\n");
}
@ -636,7 +637,7 @@ void EmitCSyms::emitScopeHier(bool destroy) {
void EmitCSyms::emitSymImp() {
UINFO(6, __FUNCTION__ << ": " << endl);
const string filename = v3Global.opt.makeDir() + "/" + symClassName() + ".cpp";
AstCFile* cfilep = newCFile(filename, true /*slow*/, true /*source*/);
AstCFile* const cfilep = newCFile(filename, true /*slow*/, true /*source*/);
cfilep->support(true);
if (v3Global.opt.systemC()) {
@ -746,7 +747,7 @@ void EmitCSyms::emitSymImp() {
for (const V3GraphVertex* vxp
= v3Global.rootp()->execGraphp()->depGraphp()->verticesBeginp();
vxp; vxp = vxp->verticesNextp()) {
ExecMTask* mtp = dynamic_cast<ExecMTask*>(const_cast<V3GraphVertex*>(vxp));
ExecMTask* const mtp = dynamic_cast<ExecMTask*>(const_cast<V3GraphVertex*>(vxp));
puts("_vm_profiler.addCounter(" + cvtToStr(mtp->profilerId()) + ", \""
+ mtp->hashName() + "\");\n");
}
@ -788,8 +789,8 @@ void EmitCSyms::emitSymImp() {
puts("// Setup each module's pointer back to symbol table (for public functions)\n");
for (const auto& i : m_scopes) {
AstScope* scopep = i.first;
AstNodeModule* modp = i.second;
AstScope* const scopep = i.first;
AstNodeModule* const modp = i.second;
checkSplit(false);
// first is used by AstCoverDecl's call to __vlCoverInsert
const bool first = !modp->user1();
@ -823,9 +824,9 @@ void EmitCSyms::emitSymImp() {
m_ofpBase->puts("// Setup export functions\n");
m_ofpBase->puts("for (int __Vfinal=0; __Vfinal<2; __Vfinal++) {\n");
for (auto it = m_scopeFuncs.begin(); it != m_scopeFuncs.end(); ++it) {
AstScopeName* scopep = it->second.m_scopep;
AstCFunc* funcp = it->second.m_cfuncp;
AstNodeModule* modp = it->second.m_modp;
AstScopeName* const scopep = it->second.m_scopep;
AstCFunc* const funcp = it->second.m_cfuncp;
AstNodeModule* const modp = it->second.m_modp;
if (funcp->dpiExportImpl()) {
checkSplit(true);
puts(protect("__Vscope_" + scopep->scopeSymName()) + ".exportInsert(__Vfinal, ");
@ -842,14 +843,14 @@ void EmitCSyms::emitSymImp() {
// Someday. For now public isn't common.
for (auto it = m_scopeVars.begin(); it != m_scopeVars.end(); ++it) {
checkSplit(true);
AstScope* scopep = it->second.m_scopep;
AstVar* varp = it->second.m_varp;
AstScope* const scopep = it->second.m_scopep;
AstVar* const varp = it->second.m_varp;
//
int pwidth = 1;
int pdim = 0;
int udim = 0;
string bounds;
if (AstBasicDType* basicp = varp->basicp()) {
if (AstBasicDType* const basicp = varp->basicp()) {
// Range is always first, it's not in "C" order
if (basicp->isRanged()) {
bounds += " ,";
@ -862,7 +863,7 @@ void EmitCSyms::emitSymImp() {
for (AstNodeDType* dtypep = varp->dtypep(); dtypep;) {
dtypep
= dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
if (const AstNodeArrayDType* adtypep = VN_CAST(dtypep, NodeArrayDType)) {
if (const AstNodeArrayDType* const adtypep = VN_CAST(dtypep, NodeArrayDType)) {
bounds += " ,";
bounds += cvtToStr(adtypep->left());
bounds += ",";
@ -964,7 +965,7 @@ void EmitCSyms::emitSymImp() {
void EmitCSyms::emitDpiHdr() {
UINFO(6, __FUNCTION__ << ": " << endl);
const string filename = v3Global.opt.makeDir() + "/" + topClassName() + "__Dpi.h";
AstCFile* cfilep = newCFile(filename, false /*slow*/, false /*source*/);
AstCFile* const cfilep = newCFile(filename, false /*slow*/, false /*source*/);
cfilep->support(true);
V3OutCFile hf(filename);
m_ofp = &hf;
@ -1018,7 +1019,7 @@ void EmitCSyms::emitDpiHdr() {
void EmitCSyms::emitDpiImp() {
UINFO(6, __FUNCTION__ << ": " << endl);
const string filename = v3Global.opt.makeDir() + "/" + topClassName() + "__Dpi.cpp";
AstCFile* cfilep = newCFile(filename, false /*slow*/, true /*source*/);
AstCFile* const cfilep = newCFile(filename, false /*slow*/, true /*source*/);
cfilep->support(true);
V3OutCFile hf(filename);
m_ofp = &hf;
@ -1052,7 +1053,7 @@ void EmitCSyms::emitDpiImp() {
puts("return " + topClassName() + "::" + nodep->name() + "(");
string args;
for (AstNode* stmtp = nodep->argsp(); stmtp; stmtp = stmtp->nextp()) {
if (const AstVar* portp = VN_CAST(stmtp, Var)) {
if (const AstVar* const portp = VN_CAST(stmtp, Var)) {
if (portp->isIO() && !portp->isFuncReturn()) {
if (args != "") args += ", ";
args += portp->name();

View File

@ -115,8 +115,8 @@ public:
} else if (support == 2 && slow) {
} else {
for (AstNodeFile* nodep = v3Global.rootp()->filesp(); nodep;
nodep = VN_CAST(nodep->nextp(), NodeFile)) {
AstCFile* cfilep = VN_CAST(nodep, CFile);
nodep = VN_AS(nodep->nextp(), NodeFile)) {
const AstCFile* const cfilep = VN_CAST(nodep, CFile);
if (cfilep && cfilep->source() && cfilep->slow() == (slow != 0)
&& cfilep->support() == (support != 0)) {
putMakeClassEntry(of, cfilep->name());
@ -145,8 +145,8 @@ public:
if (v3Global.opt.exe()) {
of.puts("default: " + v3Global.opt.exeName() + "\n");
} else if (!v3Global.opt.protectLib().empty()) {
of.puts("default: lib" + v3Global.opt.protectLib() + "\n");
} else if (!v3Global.opt.libCreate().empty()) {
of.puts("default: lib" + v3Global.opt.libCreate() + "\n");
} else {
of.puts("default: " + v3Global.opt.prefix() + "__ALL.a\n");
}
@ -188,7 +188,7 @@ public:
of.puts("# User CFLAGS (from -CFLAGS on Verilator command line)\n");
of.puts("VM_USER_CFLAGS = \\\n");
if (!v3Global.opt.protectLib().empty()) of.puts("\t-fPIC \\\n");
if (!v3Global.opt.libCreate().empty()) of.puts("\t-fPIC \\\n");
const V3StringList& cFlags = v3Global.opt.cFlags();
for (const string& i : cFlags) of.puts("\t" + i + " \\\n");
of.puts("\n");
@ -243,19 +243,19 @@ public:
of.puts("\n");
}
if (!v3Global.opt.protectLib().empty()) {
const string protectLibDeps = "$(VK_OBJS) $(VK_GLOBAL_OBJS) "
+ v3Global.opt.protectLib() + ".o $(VM_HIER_LIBS)";
of.puts("\n### Library rules from --protect-lib\n");
if (!v3Global.opt.libCreate().empty()) {
const string libCreateDeps = "$(VK_OBJS) $(VK_GLOBAL_OBJS) " + v3Global.opt.libCreate()
+ ".o $(VM_HIER_LIBS)";
of.puts("\n### Library rules from --lib-create\n");
// The rule to create .a is defined in verilated.mk, so just define dependency here.
of.puts(v3Global.opt.protectLibName(false) + ": " + protectLibDeps + "\n");
of.puts(v3Global.opt.libCreateName(false) + ": " + libCreateDeps + "\n");
of.puts("\n");
if (v3Global.opt.hierChild()) {
// Hierarchical child does not need .so because hierTop() will create .so from .a
of.puts("lib" + v3Global.opt.protectLib() + ": "
+ v3Global.opt.protectLibName(false) + "\n");
of.puts("lib" + v3Global.opt.libCreate() + ": " + v3Global.opt.libCreateName(false)
+ "\n");
} else {
of.puts(v3Global.opt.protectLibName(true) + ": " + protectLibDeps + "\n");
of.puts(v3Global.opt.libCreateName(true) + ": " + libCreateDeps + "\n");
// Linker on mac emits an error if all symbols are not found here,
// but some symbols that are referred as "DPI-C" can not be found at this moment.
// So add dynamic_lookup
@ -267,9 +267,8 @@ public:
"\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -shared -o $@ $^\n");
of.puts("endif\n");
of.puts("\n");
of.puts("lib" + v3Global.opt.protectLib() + ": "
+ v3Global.opt.protectLibName(false) + " "
+ v3Global.opt.protectLibName(true) + "\n");
of.puts("lib" + v3Global.opt.libCreate() + ": " + v3Global.opt.libCreateName(false)
+ " " + v3Global.opt.libCreateName(true) + "\n");
}
}
@ -408,7 +407,7 @@ public:
void V3EmitMk::emitmk() {
UINFO(2, __FUNCTION__ << ": " << endl);
EmitMk emitter;
const EmitMk emitter;
}
void V3EmitMk::emitHierVerilation(const V3HierBlockPlan* planp) {

View File

@ -31,7 +31,7 @@
class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
// MEMBERS
bool m_suppressSemi = false;
bool m_suppressUnknown = false;
const bool m_suppressUnknown = false;
AstSenTree* m_sensesp; // Domain for printing one a ALWAYS under a ACTIVE
// METHODS
@ -170,7 +170,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
}
virtual void visit(AstNodeCase* nodep) override {
putfs(nodep, "");
if (const AstCase* casep = VN_CAST(nodep, Case)) {
if (const AstCase* const casep = VN_CAST(nodep, Case)) {
if (casep->priorityPragma()) puts("priority ");
if (casep->uniquePragma()) puts("unique ");
if (casep->unique0Pragma()) puts("unique0 ");
@ -179,7 +179,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
puts(" (");
iterateAndNextNull(nodep->exprp());
puts(")\n");
if (const AstCase* casep = VN_CAST(nodep, Case)) {
if (const AstCase* const casep = VN_CAST(nodep, Case)) {
if (casep->fullPragma() || casep->parallelPragma()) {
puts(" // synopsys");
if (casep->fullPragma()) puts(" full_case");
@ -342,7 +342,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
}
virtual void visit(AstNodeIf* nodep) override {
putfs(nodep, "");
if (const AstIf* ifp = VN_CAST(nodep, If)) {
if (const AstIf* const ifp = VN_CAST(nodep, If)) {
if (ifp->priorityPragma()) puts("priority ");
if (ifp->uniquePragma()) puts("unique ");
if (ifp->unique0Pragma()) puts("unique0 ");
@ -382,7 +382,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
}
}
virtual void visit(AstTextBlock* nodep) override {
visit(VN_CAST(nodep, NodeSimpleText));
visit(static_cast<AstNodeSimpleText*>(nodep));
{
VL_RESTORER(m_suppressSemi);
m_suppressVarSemi = nodep->commas();
@ -416,7 +416,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
// Operators
virtual void emitVerilogFormat(AstNode* nodep, const string& format, AstNode* lhsp = nullptr,
AstNode* rhsp = nullptr, AstNode* thsp = nullptr,
AstNode* const rhsp = nullptr, AstNode* thsp = nullptr,
AstNode* fhsp = nullptr) {
// Look at emitVerilog() format for term/uni/dual/triops,
// and write out appropriate text.
@ -503,7 +503,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
if (comma++) putbs(", ");
puts(cvtToStr(itr.first));
puts(":");
AstNode* valuep = itr.second->valuep();
AstNode* const valuep = itr.second->valuep();
iterate(valuep);
}
puts("}");
@ -538,15 +538,15 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
if (VN_IS(nodep->lsbp(), Const)) {
if (nodep->widthp()->isOne()) {
if (VN_IS(nodep->lsbp(), Const)) {
puts(cvtToStr(VN_CAST(nodep->lsbp(), Const)->toSInt()));
puts(cvtToStr(VN_AS(nodep->lsbp(), Const)->toSInt()));
} else {
iterateAndNextNull(nodep->lsbp());
}
} else {
puts(cvtToStr(VN_CAST(nodep->lsbp(), Const)->toSInt()
+ VN_CAST(nodep->widthp(), Const)->toSInt() - 1));
puts(cvtToStr(VN_AS(nodep->lsbp(), Const)->toSInt()
+ VN_AS(nodep->widthp(), Const)->toSInt() - 1));
puts(":");
puts(cvtToStr(VN_CAST(nodep->lsbp(), Const)->toSInt()));
puts(cvtToStr(VN_AS(nodep->lsbp(), Const)->toSInt()));
}
} else {
iterateAndNextNull(nodep->lsbp());
@ -650,7 +650,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor {
std::vector<const AstUnpackArrayDType*> unpackps;
for (AstNodeDType* dtypep = nodep->dtypep(); dtypep;) {
dtypep = dtypep->skipRefp();
if (AstUnpackArrayDType* unpackp = VN_CAST(dtypep, UnpackArrayDType)) {
if (const AstUnpackArrayDType* const unpackp = VN_CAST(dtypep, UnpackArrayDType)) {
unpackps.push_back(unpackp);
dtypep = unpackp->subDTypep();
} else {
@ -752,8 +752,8 @@ public:
class EmitVPrefixedFormatter final : public V3OutFormatter {
std::ostream& m_os;
string m_prefix; // What to print at beginning of each line
int m_flWidth; // Padding of fileline
const string m_prefix; // What to print at beginning of each line
const int m_flWidth; // Padding of fileline
int m_column; // Rough location; need just zero or non-zero
FileLine* m_prefixFl;
// METHODS
@ -827,23 +827,25 @@ public:
//######################################################################
// EmitV class functions
void V3EmitV::verilogForTree(AstNode* nodep, std::ostream& os) { EmitVStreamVisitor(nodep, os); }
void V3EmitV::verilogForTree(AstNode* nodep, std::ostream& os) {
{ EmitVStreamVisitor{nodep, os}; }
}
void V3EmitV::verilogPrefixedTree(AstNode* nodep, std::ostream& os, const string& prefix,
int flWidth, AstSenTree* domainp, bool user3mark) {
EmitVPrefixedVisitor{nodep, os, prefix, flWidth, domainp, user3mark};
{ EmitVPrefixedVisitor{nodep, os, prefix, flWidth, domainp, user3mark}; }
}
void V3EmitV::emitvFiles() {
UINFO(2, __FUNCTION__ << ": " << endl);
for (AstNodeFile* filep = v3Global.rootp()->filesp(); filep;
filep = VN_CAST(filep->nextp(), NodeFile)) {
AstVFile* vfilep = VN_CAST(filep, VFile);
filep = VN_AS(filep->nextp(), NodeFile)) {
AstVFile* const vfilep = VN_CAST(filep, VFile);
if (vfilep && vfilep->tblockp()) {
V3OutVFile of(vfilep->name());
of.puts("// DESCR"
"IPTION: Verilator generated Verilog\n");
EmitVFileVisitor visitor{vfilep->tblockp(), &of, true, false};
{ EmitVFileVisitor{vfilep->tblockp(), &of, true, false}; }
}
}
}
@ -853,5 +855,5 @@ void V3EmitV::debugEmitV(const string& stage) {
const string filename
= v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__" + stage + ".v";
V3OutVFile of(filename);
EmitVFileVisitor visitor{v3Global.rootp(), &of, true, true};
{ EmitVFileVisitor{v3Global.rootp(), &of, true, true}; }
}

View File

@ -75,7 +75,7 @@ class EmitXmlFileVisitor final : public AstNVisitor {
puts(" tag=");
putsQuoted(nodep->tag());
}
if (AstNodeDType* dtp = VN_CAST(nodep, NodeDType)) {
if (const AstNodeDType* const dtp = VN_CAST(nodep, NodeDType)) {
if (dtp->subDTypep()) {
puts(" sub_dtype_id=");
outputId(dtp->subDTypep()->skipRefp());
@ -409,7 +409,7 @@ private:
<< nodep->fileline()->xmlDetailedLocation() << " name=\"" << nodep->name() << "\""
<< " submodname=\"" << nodep->modName() << "\""
<< " hier=\"" << m_hier + nodep->name() << "\"";
std::string hier = m_hier;
const std::string hier = m_hier;
m_hier += nodep->name() + ".";
m_hasChildren = false;
iterateChildren(nodep->modp());
@ -455,10 +455,10 @@ void V3EmitXml::emitxml() {
}
{
std::stringstream sstr;
ModuleFilesXmlVisitor moduleFilesVisitor{v3Global.rootp(), sstr};
HierCellsXmlVisitor cellsVisitor{v3Global.rootp(), sstr};
const ModuleFilesXmlVisitor moduleFilesVisitor{v3Global.rootp(), sstr};
const HierCellsXmlVisitor cellsVisitor{v3Global.rootp(), sstr};
of.puts(sstr.str());
}
EmitXmlFileVisitor visitor{v3Global.rootp(), &of};
const EmitXmlFileVisitor visitor{v3Global.rootp(), &of};
of.puts("</verilator_xml>\n");
}

View File

@ -54,7 +54,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++) {
V3ErrorCode code = V3ErrorCode(codei);
const V3ErrorCode code = V3ErrorCode(codei);
if (0 == VL_STRCASECMP(msgp, code.ascii())) {
m_e = code;
return;
@ -78,7 +78,7 @@ void V3Error::init() {
string V3Error::lineStr(const char* filename, int lineno) {
std::ostringstream out;
const char* fnslashp = std::strrchr(filename, '/');
const char* const fnslashp = std::strrchr(filename, '/');
if (fnslashp) filename = fnslashp + 1;
out << filename << ":" << std::dec << lineno << ":";
const char* const spaces = " ";
@ -131,7 +131,7 @@ bool V3Error::isError(V3ErrorCode code, bool supp) {
}
string V3Error::msgPrefix() {
V3ErrorCode code = s_errorCode;
const V3ErrorCode code = s_errorCode;
const bool supp = s_errorSuppressed;
if (supp) {
return "-arning-suppressed: ";

View File

@ -42,7 +42,7 @@ class ExpandVisitor final : public AstNVisitor {
private:
// NODE STATE
// AstNode::user1() -> bool. Processed
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// STATE
AstNode* m_stmtp = nullptr; // Current statement
@ -109,7 +109,7 @@ private:
static void fixCloneLvalue(AstNode* nodep) {
// In AstSel transforms, we call clone() on VarRefs that were lvalues,
// but are now being used on the RHS of the assignment
if (VN_IS(nodep, VarRef)) VN_CAST(nodep, VarRef)->access(VAccess::READ);
if (VN_IS(nodep, VarRef)) VN_AS(nodep, VarRef)->access(VAccess::READ);
// Iterate
if (nodep->op1p()) fixCloneLvalue(nodep->op1p());
if (nodep->op2p()) fixCloneLvalue(nodep->op2p());
@ -183,8 +183,7 @@ private:
AstNode* wordp;
FileLine* const lfl = lsbp->fileline();
if (VN_IS(lsbp, Const)) {
wordp
= new AstConst{lfl, wordOffset + VL_BITWORD_E(VN_CAST(lsbp, Const)->toUInt())};
wordp = new AstConst{lfl, wordOffset + VL_BITWORD_E(VN_AS(lsbp, Const)->toUInt())};
} else {
wordp = new AstShiftR{lfl, lsbp->cloneTree(true),
new AstConst{lfl, VL_EDATASIZE_LOG2}, VL_EDATASIZE};
@ -202,8 +201,8 @@ private:
// If there's a CONDBOUND safety to keep arrays in bounds,
// we're going to AND it to a value that always fits inside a
// word, so we don't need it.
// if (VN_IS(nodep, CondBound) && VN_IS(VN_CAST(nodep, CondBound)->lhsp(), Lte)) {
// nodep = VN_CAST(nodep, CondBound)->rhsp();
// if (VN_IS(nodep, CondBound) && VN_IS(VN_AS(nodep, CondBound)->lhsp(), Lte)) {
// nodep = VN_AS(nodep, CondBound)->rhsp();
//}
return nodep;
}
@ -212,7 +211,7 @@ private:
// Return equation to get the VL_BITBIT of a constant or non-constant
FileLine* const fl = lsbp->fileline();
if (VN_IS(lsbp, Const)) {
return new AstConst{fl, VL_BITBIT_E(VN_CAST(lsbp, Const)->toUInt())};
return new AstConst{fl, VL_BITBIT_E(VN_AS(lsbp, Const)->toUInt())};
} else {
return new AstAnd{fl, new AstConst{fl, VL_EDATASIZE - 1},
dropCondBound(lsbp)->cloneTree(true)};
@ -346,7 +345,7 @@ private:
// Remember, Sel's may have non-integer rhs, so need to optimize for that!
UASSERT_OBJ(nodep->widthMin() == nodep->widthConst(), nodep, "Width mismatch");
if (VN_IS(nodep->backp(), NodeAssign)
&& nodep == VN_CAST(nodep->backp(), NodeAssign)->lhsp()) {
&& nodep == VN_AS(nodep->backp(), NodeAssign)->lhsp()) {
// Sel is an LHS assignment select
} else if (nodep->isWide()) {
// See under ASSIGN(WIDE)
@ -679,10 +678,10 @@ private:
newp = new AstNegate{fl, lhsp};
} else {
UINFO(8, " REPLICATE " << nodep << endl);
const AstConst* constp = VN_CAST(nodep->rhsp(), Const);
const AstConst* const constp = VN_AS(nodep->rhsp(), Const);
UASSERT_OBJ(constp, nodep,
"Replication value isn't a constant. Checked earlier!");
uint32_t times = constp->toUInt();
const uint32_t times = constp->toUInt();
if (nodep->isQuad() && !lhsp->isQuad()) { lhsp = new AstCCast{fl, lhsp, nodep}; }
newp = lhsp->cloneTree(true);
for (unsigned repnum = 1; repnum < times; repnum++) {
@ -707,7 +706,7 @@ private:
FileLine* const fl = nodep->fileline();
AstNode* const lhsp = rhsp->lhsp();
const int lhswidth = lhsp->widthMin();
const AstConst* const constp = VN_CAST(rhsp->rhsp(), Const);
const AstConst* const constp = VN_AS(rhsp->rhsp(), Const);
UASSERT_OBJ(constp, rhsp, "Replication value isn't a constant. Checked earlier!");
const uint32_t times = constp->toUInt();
for (int w = 0; w < rhsp->widthWords(); ++w) {
@ -911,6 +910,6 @@ public:
void V3Expand::expandAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ ExpandVisitor visitor{nodep}; } // Destruct before checking
{ ExpandVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("expand", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -66,9 +66,9 @@ class V3FileDependImp final {
// TYPES
class DependFile final {
// A single file
bool m_target; // True if write, else read
const bool m_target; // True if write, else read
bool m_exists = true;
string m_filename; // Filename
const string m_filename; // Filename
struct stat m_stat; // Stat information
public:
DependFile(const string& filename, bool target)
@ -190,7 +190,7 @@ inline void V3FileDependImp::writeTimes(const string& filename, const string& cm
iter != m_filenameList.end(); ++iter) {
// Read stats of files we create after we're done making them
// (except for this file, of course)
DependFile* dfp = const_cast<DependFile*>(&(*iter));
DependFile* const dfp = const_cast<DependFile*>(&(*iter));
V3Options::fileNfsFlush(dfp->filename());
dfp->loadStats();
off_t showSize = iter->size();
@ -335,7 +335,7 @@ class VInFilterImp final {
#ifdef INFILTER_PIPE
pid_t m_pid = 0; // fork() process id
#else
int m_pid = 0; // fork() process id - always zero as disabled
const int m_pid = 0; // fork() process id - always zero as disabled
#endif
bool m_pidExited = false;
int m_pidStatus = 0;
@ -394,8 +394,7 @@ private:
#endif
}
string readBlocks(int fd, int size, StrList& outl) {
string out;
void readBlocks(int fd, int size, StrList& outl) {
char buf[INFILTER_IPC_BUFSIZ];
ssize_t sizegot = 0;
while (!m_readEof && (size < 0 || size > sizegot)) {
@ -421,7 +420,6 @@ private:
break;
}
}
return out;
}
// cppcheck-suppress unusedFunction unusedPrivateFunction
string readFilterLine() {
@ -634,7 +632,7 @@ string V3OutFormatter::indentSpaces(int num) {
--num;
}
*cp++ = '\0';
string st(str);
string st{str}; // No const, move optimization
return st;
}
@ -1055,7 +1053,7 @@ public:
private:
void trySep(const string& old, string::size_type start, const string& trySep,
string::size_type& posr, string& separatorr) {
string::size_type trypos = old.find(trySep, start);
const string::size_type trypos = old.find(trySep, start);
if (trypos != string::npos) {
if (posr == string::npos || (posr > trypos)) {
posr = trypos;

View File

@ -113,8 +113,8 @@ public:
private:
// MEMBERS
string m_filename;
Language m_lang; // Indenting Verilog code
const string m_filename;
const Language m_lang; // Indenting Verilog code
int m_blockIndent; // Characters per block indent
int m_commaWidth; // Width after which to break at ,'s
int m_lineno = 1;

View File

@ -101,9 +101,9 @@ void VFileContent::pushText(const string& text) {
// Insert line-by-line
string::size_type line_start = 0;
while (true) {
string::size_type line_end = leftover.find('\n', line_start);
const string::size_type line_end = leftover.find('\n', line_start);
if (line_end != string::npos) {
string oneline(leftover, line_start, line_end - line_start + 1);
const string oneline(leftover, line_start, line_end - line_start + 1);
m_lines.push_back(oneline); // Keeps newline
UINFO(9, "PushStream[ct" << m_id << "+" << (m_lines.size() - 1) << "]: " << oneline);
line_start = line_end + 1;
@ -148,7 +148,7 @@ FileLine::FileLine(FileLine::EmptySecret) {
m_warnOn = 0;
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
V3ErrorCode code = V3ErrorCode(codei);
const V3ErrorCode code = V3ErrorCode(codei);
warnOff(code, code.defaultsOff());
}
}
@ -181,7 +181,7 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) {
// Grab linenumber
bool fail = false;
const char* ln = textp;
const char* const ln = textp;
while (*textp && !isspace(*textp)) textp++;
if (isdigit(*ln)) {
lineno(atoi(ln));
@ -193,7 +193,7 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) {
while (*textp && (isspace(*textp) || *textp == '"')) textp++;
// Grab filename
const char* fn = textp;
const char* const fn = textp;
while (*textp && !(isspace(*textp) || *textp == '"')) textp++;
if (textp != fn) {
string strfn = fn;
@ -244,7 +244,7 @@ FileLine* FileLine::copyOrSameFileLine() {
if (lastNewp && *lastNewp == *this) { // Compares lineno, filename, etc
return lastNewp;
}
FileLine* newp = new FileLine(this);
FileLine* const newp = new FileLine(this);
lastNewp = newp;
return newp;
}
@ -264,8 +264,8 @@ string FileLine::filebasenameNoExt() const {
}
string FileLine::firstColumnLetters() const {
char a = ((firstColumn() / 26) % 26) + 'a';
char b = (firstColumn() % 26) + 'a';
const char a = ((firstColumn() / 26) % 26) + 'a';
const char b = (firstColumn() % 26) + 'a';
return string(1, a) + string(1, b);
}
@ -297,7 +297,7 @@ std::ostream& operator<<(std::ostream& os, FileLine* fileline) {
}
bool FileLine::warnOff(const string& msg, bool flag) {
V3ErrorCode code(msg.c_str());
const V3ErrorCode code(msg.c_str());
if (code < V3ErrorCode::EC_FIRST_WARN) {
return false;
} else {
@ -308,14 +308,14 @@ bool FileLine::warnOff(const string& msg, bool flag) {
void FileLine::warnLintOff(bool flag) {
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
V3ErrorCode code = V3ErrorCode(codei);
const V3ErrorCode code = V3ErrorCode(codei);
if (code.lintError()) warnOff(code, flag);
}
}
void FileLine::warnStyleOff(bool flag) {
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
V3ErrorCode code = V3ErrorCode(codei);
const V3ErrorCode code = V3ErrorCode(codei);
if (code.styleError()) warnOff(code, flag);
}
}
@ -334,7 +334,7 @@ bool FileLine::warnIsOff(V3ErrorCode code) const {
void FileLine::modifyStateInherit(const FileLine* fromp) {
// Any warnings that are off in "from", become off in "this".
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
V3ErrorCode code = V3ErrorCode(codei);
const V3ErrorCode code = V3ErrorCode(codei);
if (fromp->warnIsOff(code)) warnOff(code, true);
}
}
@ -388,7 +388,7 @@ string FileLine::source() const {
string FileLine::prettySource() const {
string out = source();
// Drop ignore trailing newline
string::size_type pos = out.find('\n');
const string::size_type pos = out.find('\n');
if (pos != string::npos) out = string(out, 0, pos);
// Column tracking counts tabs = 1, so match that when print source
return VString::spaceUnprintable(out);
@ -430,14 +430,14 @@ string FileLine::warnContext(bool secondary) const {
std::unordered_set<FileLine*> fileLineLeakChecks;
void* FileLine::operator new(size_t size) {
FileLine* objp = static_cast<FileLine*>(::operator new(size));
FileLine* const objp = static_cast<FileLine*>(::operator new(size));
fileLineLeakChecks.insert(objp);
return objp;
}
void FileLine::operator delete(void* objp, size_t size) {
if (!objp) return;
FileLine* flp = static_cast<FileLine*>(objp);
FileLine* const flp = static_cast<FileLine*>(objp);
const auto it = fileLineLeakChecks.find(flp);
if (it != fileLineLeakChecks.end()) {
fileLineLeakChecks.erase(it);

View File

@ -67,7 +67,7 @@ public:
// Support classes
class GateEitherVertex VL_NOT_FINAL : public V3GraphVertex {
AstScope* m_scopep; // Scope vertex refers to
AstScope* const m_scopep; // Scope vertex refers to
bool m_reducible = true; // True if this node should be able to be eliminated
bool m_dedupable = true; // True if this node should be able to be deduped
bool m_consumed = false; // Output goes to something meaningful
@ -124,7 +124,7 @@ public:
};
class GateVarVertex final : public GateEitherVertex {
AstVarScope* m_varScp;
AstVarScope* const m_varScp;
bool m_isTop = false;
bool m_isClock = false;
AstNode* m_rstSyncNodep = nullptr; // Used as reset and not in SenItem, in clocked always
@ -164,9 +164,9 @@ public:
};
class GateLogicVertex final : public GateEitherVertex {
AstNode* m_nodep;
AstActive* m_activep; // Under what active; nullptr is ok (under cfunc or such)
bool m_slow; // In slow block
AstNode* const m_nodep;
AstActive* const m_activep; // Under what active; nullptr is ok (under cfunc or such)
const bool m_slow; // In slow block
public:
GateLogicVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep, AstActive* activep,
bool slow)
@ -200,7 +200,8 @@ private:
AstNode* m_substTreep = nullptr; // What to replace the variable with
// STATE
bool m_buffersOnly; // Set when we only allow simple buffering, no equations (for clocks)
AstNodeVarRef* m_lhsVarRef = nullptr; // VarRef on lhs of assignment (what we're replacing)
const AstNodeVarRef* m_lhsVarRef
= nullptr; // VarRef on lhs of assignment (what we're replacing)
bool m_dedupe; // Set when we use isGateDedupable instead of isGateOptimizable
int m_ops = 0; // Operation count
@ -227,7 +228,7 @@ private:
m_lhsVarRef = nodep;
} else {
if (m_rhsVarRefs.size() > 1) {
AstNodeVarRef* lastRefp = m_rhsVarRefs.back();
const AstNodeVarRef* const lastRefp = m_rhsVarRefs.back();
if (m_buffersOnly) clearSimple(">1 rhs varRefs");
if (!nodep->varScopep()->varp()->gateMultiInputOptimizable()
// We didn't check multiInput on the first varref, so check it here
@ -249,14 +250,12 @@ private:
// This avoids a mess in computing what exactly a POSEDGE is
// V3Const cleans up any NOTs by flipping the edges for us
if (m_buffersOnly
&& !(VN_IS(nodep->rhsp(), VarRef)
// Avoid making non-clocked logic into clocked,
// as it slows down the verilator_sim_benchmark
|| (VN_IS(nodep->rhsp(), Not)
&& VN_IS(VN_CAST(nodep->rhsp(), Not)->lhsp(), VarRef)
&& VN_CAST(VN_CAST(nodep->rhsp(), Not)->lhsp(), VarRef)
->varp()
->isUsedClock()))) {
&& !(
VN_IS(nodep->rhsp(), VarRef)
// Avoid making non-clocked logic into clocked,
// as it slows down the verilator_sim_benchmark
|| (VN_IS(nodep->rhsp(), Not) && VN_IS(VN_AS(nodep->rhsp(), Not)->lhsp(), VarRef)
&& VN_AS(VN_AS(nodep->rhsp(), Not)->lhsp(), VarRef)->varp()->isUsedClock()))) {
clearSimple("Not a buffer (goes to a clock)");
}
}
@ -310,14 +309,14 @@ private:
// AstVarScope::user2 -> bool: Signal used in SenItem in *this* always statement
// AstVar::user2 -> bool: Warned about SYNCASYNCNET
// AstNodeVarRef::user2 -> bool: ConcatOffset visited
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
const AstUser1InUse m_inuser1;
const AstUser2InUse m_inuser2;
// STATE
V3Graph m_graph; // Scoreboard of var usages/dependencies
GateLogicVertex* m_logicVertexp = nullptr; // Current statement being tracked, nullptr=ignored
AstScope* m_scopep = nullptr; // Current scope being processed
AstNodeModule* m_modp = nullptr; // Current module
const AstNodeModule* m_modp = nullptr; // Current module
AstActive* m_activep = nullptr; // Current active
bool m_activeReducible = true; // Is activation block reducible?
bool m_inSenItem = false; // Underneath AstSenItem; any varrefs are clocks
@ -442,9 +441,9 @@ private:
virtual void visit(AstNodeVarRef* nodep) override {
if (m_scopep) {
UASSERT_OBJ(m_logicVertexp, nodep, "Var ref not under a logic block");
AstVarScope* varscp = nodep->varScopep();
AstVarScope* const varscp = nodep->varScopep();
UASSERT_OBJ(varscp, nodep, "Var didn't get varscoped in V3Scope.cpp");
GateVarVertex* vvertexp = makeVarVertex(varscp);
GateVarVertex* const vvertexp = makeVarVertex(varscp);
UINFO(5, " VARREF to " << varscp << endl);
if (m_inSenItem) {
vvertexp->setIsClock();
@ -512,7 +511,7 @@ private:
}
virtual void visit(AstConcat* nodep) override {
UASSERT_OBJ(!(VN_IS(nodep->backp(), NodeAssign)
&& VN_CAST(nodep->backp(), NodeAssign)->lhsp() == nodep),
&& VN_AS(nodep->backp(), NodeAssign)->lhsp() == nodep),
nodep, "Concat on LHS of assignment; V3Const should have deleted it");
iterateChildren(nodep);
}
@ -538,7 +537,7 @@ public:
void GateVisitor::optimizeSignals(bool allowMultiIn) {
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
if (GateVarVertex* const vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
if (vvertexp->inEmpty()) {
vvertexp->clearReducibleAndDedupable("inEmpty"); // Can't deal with no sources
if (!vvertexp->isTop() // Ok if top inputs are driverless
@ -564,13 +563,13 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
UINFO(8, "SigNotRed " << vvertexp->name() << endl);
} else {
UINFO(8, "Sig " << vvertexp->name() << endl);
GateLogicVertex* logicVertexp
GateLogicVertex* const logicVertexp
= dynamic_cast<GateLogicVertex*>(vvertexp->inBeginp()->fromp());
UINFO(8, " From " << logicVertexp->name() << endl);
AstNode* logicp = logicVertexp->nodep();
if (logicVertexp->reducible()) {
// Can we eliminate?
GateOkVisitor okVisitor{logicp, vvertexp->isClock(), false};
const GateOkVisitor okVisitor{logicp, vvertexp->isClock(), false};
const bool multiInputs = okVisitor.rhsVarRefs().size() > 1;
// Was it ok?
bool doit = okVisitor.isSimple();
@ -580,7 +579,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
int n = 0;
for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep;
edgep = edgep->outNextp()) {
GateLogicVertex* consumeVertexp
const GateLogicVertex* const consumeVertexp
= dynamic_cast<GateLogicVertex*>(edgep->top());
if (!consumeVertexp->slow()) { // Not tracing or other slow path junk
if (edgep->top()->outBeginp()) { // Destination is itself used
@ -604,29 +603,29 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
<< " " << vvertexp->name() << endl);
for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep;
edgep = edgep->outNextp()) {
GateLogicVertex* consumeVertexp
const GateLogicVertex* const consumeVertexp
= dynamic_cast<GateLogicVertex*>(edgep->top());
UINFO(9, " edge " << edgep << " to: " << consumeVertexp->nodep()
<< endl);
}
for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep;
edgep = edgep->inNextp()) {
GateLogicVertex* consumeVertexp
const GateLogicVertex* const consumeVertexp
= dynamic_cast<GateLogicVertex*>(edgep->fromp());
UINFO(9, " edge " << edgep << " from: "
<< consumeVertexp->nodep() << endl);
}
}
} else {
AstNode* substp = okVisitor.substTree();
AstNode* const substp = okVisitor.substTree();
if (debug() >= 5) logicp->dumpTree(cout, " elimVar: ");
if (debug() >= 5) substp->dumpTree(cout, " subst: ");
++m_statSigs;
bool removedAllUsages = true;
for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep;) {
GateLogicVertex* consumeVertexp
GateLogicVertex* const consumeVertexp
= dynamic_cast<GateLogicVertex*>(edgep->top());
AstNode* consumerp = consumeVertexp->nodep();
AstNode* const consumerp = consumeVertexp->nodep();
if (!elimLogicOkOutputs(consumeVertexp, okVisitor /*ref*/)) {
// Cannot optimize this replacement
removedAllUsages = false;
@ -638,9 +637,9 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
const GateVarRefList& rhsVarRefs = okVisitor.rhsVarRefs();
for (GateVarRefList::const_iterator it = rhsVarRefs.begin();
it != rhsVarRefs.end(); ++it) {
AstVarScope* newvarscp = (*it)->varScopep();
AstVarScope* const newvarscp = (*it)->varScopep();
UINFO(9, " Point-to-new vertex " << newvarscp << endl);
GateVarVertex* varvertexp = makeVarVertex(newvarscp);
GateVarVertex* const varvertexp = makeVarVertex(newvarscp);
new V3GraphEdge(&m_graph, varvertexp, consumeVertexp, 1);
// Propagate clock attribute onto generating node
varvertexp->propagateAttrClocksFrom(vvertexp);
@ -653,7 +652,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
}
if (removedAllUsages) {
// Remove input links
while (V3GraphEdge* edgep = vvertexp->inBeginp()) {
while (V3GraphEdge* const edgep = vvertexp->inBeginp()) {
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
}
// Clone tree so we remember it for tracing, and keep the pointer
@ -687,12 +686,12 @@ bool GateVisitor::elimLogicOkOutputs(GateLogicVertex* consumeVertexp,
// Replacement logic usually has shorter input list, so faster to build list based on it
const GateVarRefList& rhsVarRefs = okVisitor.rhsVarRefs();
for (GateVarRefList::const_iterator it = rhsVarRefs.begin(); it != rhsVarRefs.end(); ++it) {
AstVarScope* vscp = (*it)->varScopep();
AstVarScope* const vscp = (*it)->varScopep();
varscopes.insert(vscp);
}
for (V3GraphEdge* edgep = consumeVertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
GateVarVertex* consVVertexp = dynamic_cast<GateVarVertex*>(edgep->top());
AstVarScope* vscp = consVVertexp->varScp();
const GateVarVertex* const consVVertexp = dynamic_cast<GateVarVertex*>(edgep->top());
AstVarScope* const vscp = consVVertexp->varScp();
if (varscopes.find(vscp) != varscopes.end()) {
UINFO(9, " Block-unopt, insertion generates input vscp " << vscp << endl);
return false;
@ -703,29 +702,29 @@ bool GateVisitor::elimLogicOkOutputs(GateLogicVertex* consumeVertexp,
void GateVisitor::replaceAssigns() {
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
if (const GateVarVertex* const vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
// Take the Comments/assigns that were moved to the VarScope and change them to a
// simple value assignment
AstVarScope* vscp = vvertexp->varScp();
const AstVarScope* const vscp = vvertexp->varScp();
if (vscp->valuep() && !VN_IS(vscp->valuep(), NodeMath)) {
// if (debug() > 9) vscp->dumpTree(cout, "-vscPre: ");
while (AstNode* delp = VN_CAST(vscp->valuep(), Comment)) {
VL_DO_DANGLING(delp->unlinkFrBack()->deleteTree(), delp);
}
if (AstInitial* delp = VN_CAST(vscp->valuep(), Initial)) {
AstNode* bodyp = delp->bodysp();
if (AstInitial* const delp = VN_CAST(vscp->valuep(), Initial)) {
AstNode* const bodyp = delp->bodysp();
bodyp->unlinkFrBackWithNext();
delp->replaceWith(bodyp);
VL_DO_DANGLING(delp->deleteTree(), delp);
}
if (AstAlways* delp = VN_CAST(vscp->valuep(), Always)) {
AstNode* bodyp = delp->bodysp();
if (AstAlways* const delp = VN_CAST(vscp->valuep(), Always)) {
AstNode* const bodyp = delp->bodysp();
bodyp->unlinkFrBackWithNext();
delp->replaceWith(bodyp);
VL_DO_DANGLING(delp->deleteTree(), delp);
}
if (AstNodeAssign* delp = VN_CAST(vscp->valuep(), NodeAssign)) {
AstNode* rhsp = delp->rhsp();
if (AstNodeAssign* const delp = VN_CAST(vscp->valuep(), NodeAssign)) {
AstNode* const rhsp = delp->rhsp();
rhsp->unlinkFrBack();
delp->replaceWith(rhsp);
VL_DO_DANGLING(delp->deleteTree(), delp);
@ -747,7 +746,7 @@ void GateVisitor::consumedMark() {
m_graph.userClearVertices();
for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp;
vertexp = vertexp->verticesNextp()) {
GateEitherVertex* evertexp = static_cast<GateEitherVertex*>(vertexp);
GateEitherVertex* const evertexp = static_cast<GateEitherVertex*>(vertexp);
if (!evertexp->user() && evertexp->consumed()) consumedMarkRecurse(evertexp);
}
}
@ -758,7 +757,7 @@ void GateVisitor::consumedMarkRecurse(GateEitherVertex* vertexp) {
if (!vertexp->consumed()) vertexp->setConsumed("propagated");
// Walk sources and mark them too
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
GateEitherVertex* eFromVertexp = static_cast<GateEitherVertex*>(edgep->fromp());
GateEitherVertex* const eFromVertexp = static_cast<GateEitherVertex*>(edgep->fromp());
consumedMarkRecurse(eFromVertexp);
}
}
@ -768,14 +767,14 @@ void GateVisitor::consumedMove() {
// We need the "usually" block logic to do a better job at this
for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp;
vertexp = vertexp->verticesNextp()) {
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(vertexp)) {
if (const GateVarVertex* const vvertexp = dynamic_cast<GateVarVertex*>(vertexp)) {
if (!vvertexp->consumed() && !vvertexp->user()) {
UINFO(8, "Unconsumed " << vvertexp->varScp() << endl);
}
}
if (GateLogicVertex* lvertexp = dynamic_cast<GateLogicVertex*>(vertexp)) {
AstNode* nodep = lvertexp->nodep();
AstActive* oldactp = lvertexp->activep(); // nullptr under cfunc
if (const GateLogicVertex* const lvertexp = dynamic_cast<GateLogicVertex*>(vertexp)) {
AstNode* const nodep = lvertexp->nodep();
const AstActive* const oldactp = lvertexp->activep(); // nullptr under cfunc
if (!lvertexp->consumed() && oldactp) {
// Eventually: Move the statement to a new active block
// with "tracing-on" sensitivity
@ -792,10 +791,10 @@ void GateVisitor::consumedMove() {
void GateVisitor::warnSignals() {
AstNode::user2ClearTree();
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
AstVarScope* vscp = vvertexp->varScp();
AstNode* sp = vvertexp->rstSyncNodep();
AstNode* ap = vvertexp->rstAsyncNodep();
if (const GateVarVertex* const vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
const AstVarScope* const vscp = vvertexp->varScp();
const AstNode* const sp = vvertexp->rstSyncNodep();
const AstNode* const ap = vvertexp->rstAsyncNodep();
if (ap && sp && !vscp->varp()->user2()) {
// This is somewhat wrong, as marking one flop as ok for sync
// may mean a different flop now fails. However it's a pain to
@ -827,7 +826,7 @@ class GateElimVisitor final : public GateBaseVisitor {
private:
// NODE STATE
// STATE
AstVarScope* m_elimVarScp; // Variable being eliminated
const AstVarScope* m_elimVarScp; // Variable being eliminated
AstNode* m_replaceTreep; // What to replace the variable with
bool m_didReplace; // Did we do any replacements
GateDedupeVarVisitor* m_varVisp; // Callback to keep hash up to date
@ -844,11 +843,10 @@ private:
m_didReplace = true;
UASSERT_OBJ(nodep->access().isReadOnly(), nodep,
"Can't replace lvalue assignments with const var");
AstNode* substp = m_replaceTreep->cloneTree(false);
UASSERT_OBJ(
!(VN_IS(nodep, NodeVarRef) && VN_IS(substp, NodeVarRef) && nodep->same(substp)),
// Prevent an infinite loop...
substp, "Replacing node with itself; perhaps circular logic?");
AstNode* const substp = m_replaceTreep->cloneTree(false);
UASSERT_OBJ(!(VN_IS(substp, NodeVarRef) && nodep->same(substp)),
// Prevent an infinite loop...
substp, "Replacing node with itself; perhaps circular logic?");
// Which fileline() to use?
// If replacing with logic, an error/warning is likely to want to point to the logic
// IE what we're replacing with.
@ -856,7 +854,7 @@ private:
// to throw warnings that point to a PIN rather than where the pin us used.
if (VN_IS(substp, VarRef)) substp->fileline(nodep->fileline());
// Make the substp an rvalue like nodep. This facilitates the hashing in dedupe.
if (AstNodeVarRef* varrefp = VN_CAST(substp, NodeVarRef))
if (AstNodeVarRef* const varrefp = VN_CAST(substp, NodeVarRef))
varrefp->access(VAccess::READ);
hashReplace(nodep, substp);
nodep->replaceWith(substp);
@ -884,7 +882,7 @@ public:
void GateVisitor::optimizeElimVar(AstVarScope* varscp, AstNode* substp, AstNode* consumerp) {
if (debug() >= 5) consumerp->dumpTree(cout, " elimUsePre: ");
GateElimVisitor elimVisitor{consumerp, varscp, substp, nullptr};
const GateElimVisitor elimVisitor{consumerp, varscp, substp, nullptr};
if (elimVisitor.didReplace()) {
if (debug() >= 9) consumerp->dumpTree(cout, " elimUseCns: ");
// Caution: Can't let V3Const change our handle to consumerp, such as by
@ -910,9 +908,9 @@ private:
// Set to nullptr if this assign's tree was later replaced
// AstUser1InUse m_inuser1; (Allocated for use in GateVisitor)
// AstUser2InUse m_inuser2; (Allocated for use in GateVisitor)
AstUser3InUse m_inuser3;
const AstUser3InUse m_inuser3;
// AstUser4InUse m_inuser4; (Allocated for use in V3Hasher via V3DupFinder)
AstUser5InUse m_inuser5;
const AstUser5InUse m_inuser5;
V3DupFinder m_dupFinder; // Duplicate finder for rhs of assigns
std::unordered_set<AstNode*> m_nodeDeleteds; // Any node in this hash was deleted
@ -964,8 +962,8 @@ public:
bool isReplaced(AstNode* nodep) {
// Assignment may have been hashReplaced, if so consider non-match (effectively removed)
UASSERT_OBJ(!VN_IS(nodep, NodeAssign), nodep, "Dedup attempt on non-assign");
AstNode* extra1p = nodep->user3p();
AstNode* extra2p = nodep->user5p();
AstNode* const extra1p = nodep->user3p();
AstNode* const extra2p = nodep->user5p();
return ((extra1p && m_nodeDeleteds.find(extra1p) != m_nodeDeleteds.end())
|| (extra2p && m_nodeDeleteds.find(extra2p) != m_nodeDeleteds.end()));
}
@ -981,10 +979,11 @@ public:
&& node1p->user2p()->type() == node2p->user2p()->type();
}
AstNodeAssign* hashAndFindDupe(AstNodeAssign* assignp, AstNode* extra1p, AstNode* extra2p) {
const AstNodeAssign* hashAndFindDupe(AstNodeAssign* assignp, AstNode* extra1p,
AstNode* extra2p) {
// Legal for extra1p/2p to be nullptr, we'll compare with other assigns with extras also
// nullptr
AstNode* rhsp = assignp->rhsp();
AstNode* const rhsp = assignp->rhsp();
rhsp->user2p(assignp);
rhsp->user3p(extra1p);
rhsp->user5p(extra2p);
@ -996,7 +995,7 @@ public:
// So dupit is either a different, duplicate rhsp, or the end of the hash.
if (dupit != m_dupFinder.end()) {
m_dupFinder.erase(inserted);
return VN_CAST(dupit->second->user2p(), NodeAssign);
return VN_AS(dupit->second->user2p(), NodeAssign);
}
// Retain new inserted information
return nullptr;
@ -1004,9 +1003,9 @@ public:
void check() {
for (const auto& itr : m_dupFinder) {
AstNode* nodep = itr.second;
AstNode* activep = nodep->user3p();
AstNode* condVarp = nodep->user5p();
AstNode* const nodep = itr.second;
const AstNode* const activep = nodep->user3p();
const AstNode* const condVarp = nodep->user5p();
if (!isReplaced(nodep)) {
// This class won't break if activep isn't an active, or
// ifVar isn't a var, but this is checking the caller's construction.
@ -1097,12 +1096,13 @@ public:
m_dedupable = true;
iterate(nodep);
if (m_dedupable && m_assignp) {
AstNode* lhsp = m_assignp->lhsp();
const AstNode* const lhsp = m_assignp->lhsp();
// Possible todo, handle more complex lhs expressions
if (AstNodeVarRef* lhsVarRefp = VN_CAST(lhsp, NodeVarRef)) {
if (const AstNodeVarRef* const lhsVarRefp = VN_CAST(lhsp, NodeVarRef)) {
UASSERT_OBJ(lhsVarRefp->varScopep() == consumerVarScopep, consumerVarScopep,
"Consumer doesn't match lhs of assign");
if (AstNodeAssign* dup = m_ghash.hashAndFindDupe(m_assignp, activep, m_ifCondp)) {
if (const AstNodeAssign* const dup
= m_ghash.hashAndFindDupe(m_assignp, activep, m_ifCondp)) {
return static_cast<AstNodeVarRef*>(dup->lhsp());
}
}
@ -1140,26 +1140,26 @@ private:
m_depth++;
if (vvertexp->inSize1()) {
AstNodeVarRef* dupVarRefp = static_cast<AstNodeVarRef*>(
AstNodeVarRef* const dupVarRefp = static_cast<AstNodeVarRef*>(
vvertexp->iterateInEdges(*this, VNUser(vvertexp)).toNodep());
if (dupVarRefp) { // visit(GateLogicVertex*...) returned match
V3GraphEdge* edgep = vvertexp->inBeginp();
GateLogicVertex* lvertexp = static_cast<GateLogicVertex*>(edgep->fromp());
const V3GraphEdge* edgep = vvertexp->inBeginp();
GateLogicVertex* const lvertexp = static_cast<GateLogicVertex*>(edgep->fromp());
UASSERT_OBJ(vvertexp->dedupable(), vvertexp->varScp(),
"GateLogicVertex* visit should have returned nullptr "
"if consumer var vertex is not dedupable.");
GateOkVisitor okVisitor{lvertexp->nodep(), false, true};
const GateOkVisitor okVisitor{lvertexp->nodep(), false, true};
if (okVisitor.isSimple()) {
AstVarScope* dupVarScopep = dupVarRefp->varScopep();
GateVarVertex* dupVvertexp
const AstVarScope* const dupVarScopep = dupVarRefp->varScopep();
GateVarVertex* const dupVvertexp
= reinterpret_cast<GateVarVertex*>(dupVarScopep->user1p());
UINFO(4, "replacing " << vvertexp << " with " << dupVvertexp << endl);
++m_numDeduped;
// Replace all of this varvertex's consumers with dupVarRefp
for (V3GraphEdge* outedgep = vvertexp->outBeginp(); outedgep;) {
GateLogicVertex* consumeVertexp
const GateLogicVertex* const consumeVertexp
= dynamic_cast<GateLogicVertex*>(outedgep->top());
AstNode* consumerp = consumeVertexp->nodep();
AstNode* const consumerp = consumeVertexp->nodep();
// if (debug() >= 9) m_graphp->dumpDotFilePrefixed("gate_preelim");
UINFO(9,
"elim src vtx" << lvertexp << " node " << lvertexp->nodep() << endl);
@ -1171,15 +1171,15 @@ private:
if (lvertexp == consumeVertexp) {
UINFO(9, "skipping as self-recirculates\n");
} else {
GateElimVisitor elimVisitor(consumerp, vvertexp->varScp(), dupVarRefp,
&m_varVisitor);
const GateElimVisitor elimVisitor(consumerp, vvertexp->varScp(),
dupVarRefp, &m_varVisitor);
}
outedgep = outedgep->relinkFromp(dupVvertexp);
}
// Propagate attributes
dupVvertexp->propagateAttrClocksFrom(vvertexp);
// Remove inputs links
while (V3GraphEdge* inedgep = vvertexp->inBeginp()) {
while (V3GraphEdge* const inedgep = vvertexp->inBeginp()) {
VL_DO_DANGLING(inedgep->unlinkDelete(), inedgep);
}
// replaceAssigns() does the deleteTree on lvertexNodep in a later step
@ -1201,15 +1201,16 @@ private:
virtual VNUser visit(GateLogicVertex* lvertexp, VNUser vu) override {
lvertexp->iterateInEdges(*this);
GateVarVertex* consumerVvertexpp = static_cast<GateVarVertex*>(vu.toGraphVertex());
const GateVarVertex* const consumerVvertexpp
= static_cast<GateVarVertex*>(vu.toGraphVertex());
if (lvertexp->dedupable() && consumerVvertexpp->dedupable()) {
AstNode* nodep = lvertexp->nodep();
AstVarScope* consumerVarScopep = consumerVvertexpp->varScp();
AstNode* const nodep = lvertexp->nodep();
AstVarScope* const consumerVarScopep = consumerVvertexpp->varScp();
// TODO: Doing a simple pointer comparison of activep won't work
// optimally for statements under generated clocks. Statements under
// different generated clocks will never compare as equal, even if the
// generated clocks are deduped into one clock.
AstActive* activep = lvertexp->activep();
AstActive* const activep = lvertexp->activep();
return VNUser(m_varVisitor.findDupe(nodep, consumerVarScopep, activep));
}
return VNUser(0);
@ -1230,14 +1231,14 @@ void GateVisitor::dedupe() {
// Traverse starting from each of the clocks
UINFO(9, "Gate dedupe() clocks:\n");
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
if (GateVarVertex* const vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
if (vvertexp->isClock()) deduper.dedupeTree(vvertexp);
}
}
// Traverse starting from each of the outputs
UINFO(9, "Gate dedupe() outputs:\n");
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
if (GateVarVertex* const vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
if (vvertexp->isTop() && vvertexp->varScp()->varp()->isWritable()) {
deduper.dedupeTree(vvertexp);
}
@ -1253,21 +1254,21 @@ class GateMergeAssignsGraphVisitor final : public GateGraphBaseVisitor {
private:
// NODE STATE
AstNodeAssign* m_assignp = nullptr;
AstActive* m_activep = nullptr;
const AstActive* m_activep = nullptr;
GateLogicVertex* m_logicvp = nullptr;
VDouble0 m_numMergedAssigns; // Statistic tracking
// assemble two Sel into one if possible
AstSel* merge(AstSel* pre, AstSel* cur) {
AstVarRef* preVarRefp = VN_CAST(pre->fromp(), VarRef);
AstVarRef* curVarRefp = VN_CAST(cur->fromp(), VarRef);
const AstVarRef* const preVarRefp = VN_CAST(pre->fromp(), VarRef);
AstVarRef* const curVarRefp = VN_CAST(cur->fromp(), VarRef);
if (!preVarRefp || !curVarRefp || !curVarRefp->same(preVarRefp)) {
return nullptr; // not the same var
}
const AstConst* pstart = VN_CAST(pre->lsbp(), Const);
const AstConst* pwidth = VN_CAST(pre->widthp(), Const);
const AstConst* cstart = VN_CAST(cur->lsbp(), Const);
const AstConst* cwidth = VN_CAST(cur->widthp(), Const);
const AstConst* const pstart = VN_CAST(pre->lsbp(), Const);
const AstConst* const pwidth = VN_CAST(pre->widthp(), Const);
const AstConst* const cstart = VN_CAST(cur->lsbp(), Const);
const AstConst* const cwidth = VN_CAST(cur->widthp(), Const);
if (!pstart || !pwidth || !cstart || !cwidth) return nullptr; // too complicated
if (cur->lsbConst() + cur->widthConst() == pre->lsbConst()) {
return new AstSel(curVarRefp->fileline(), curVarRefp->cloneTree(false),
@ -1281,12 +1282,13 @@ private:
for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep;) {
V3GraphEdge* oldedgep = edgep;
edgep = edgep->inNextp(); // for recursive since the edge could be deleted
if (GateLogicVertex* lvertexp = dynamic_cast<GateLogicVertex*>(oldedgep->fromp())) {
if (AstNodeAssign* assignp = VN_CAST(lvertexp->nodep(), NodeAssign)) {
if (GateLogicVertex* const lvertexp
= dynamic_cast<GateLogicVertex*>(oldedgep->fromp())) {
if (AstNodeAssign* const assignp = VN_CAST(lvertexp->nodep(), NodeAssign)) {
// if (lvertexp->outSize1() && VN_IS(assignp->lhsp(), Sel)) {
if (VN_IS(assignp->lhsp(), Sel) && lvertexp->outSize1()) {
UINFO(9, "assing to the nodep["
<< VN_CAST(assignp->lhsp(), Sel)->lsbConst() << "]" << endl);
UINFO(9, "assing to the nodep[" << VN_AS(assignp->lhsp(), Sel)->lsbConst()
<< "]" << endl);
// first assign with Sel-lhs
if (!m_activep) m_activep = lvertexp->activep();
if (!m_logicvp) m_logicvp = lvertexp;
@ -1300,20 +1302,20 @@ private:
continue;
}
AstSel* preselp = VN_CAST(m_assignp->lhsp(), Sel);
AstSel* curselp = VN_CAST(assignp->lhsp(), Sel);
AstSel* const preselp = VN_CAST(m_assignp->lhsp(), Sel);
AstSel* const curselp = VN_CAST(assignp->lhsp(), Sel);
if (!preselp || !curselp) continue;
if (AstSel* newselp = merge(preselp, curselp)) {
if (AstSel* const newselp = merge(preselp, curselp)) {
UINFO(5, "assemble to new sel: " << newselp << endl);
// replace preSel with newSel
preselp->replaceWith(newselp);
VL_DO_DANGLING(preselp->deleteTree(), preselp);
// create new rhs for pre assignment
AstNode* newrhsp = new AstConcat(m_assignp->rhsp()->fileline(),
m_assignp->rhsp()->cloneTree(false),
assignp->rhsp()->cloneTree(false));
AstNode* oldrhsp = m_assignp->rhsp();
AstNode* const newrhsp = new AstConcat(
m_assignp->rhsp()->fileline(), m_assignp->rhsp()->cloneTree(false),
assignp->rhsp()->cloneTree(false));
AstNode* const oldrhsp = m_assignp->rhsp();
oldrhsp->replaceWith(newrhsp);
VL_DO_DANGLING(oldrhsp->deleteTree(), oldrhsp);
m_assignp->dtypeChgWidthSigned(m_assignp->width() + assignp->width(),
@ -1330,7 +1332,7 @@ private:
for (V3GraphEdge* ledgep = lvertexp->inBeginp(); ledgep;) {
V3GraphEdge* oedgep = ledgep;
ledgep = ledgep->inNextp();
GateEitherVertex* fromvp
GateEitherVertex* const fromvp
= dynamic_cast<GateEitherVertex*>(oedgep->fromp());
new V3GraphEdge(m_graphp, fromvp, m_logicvp, 1);
VL_DO_DANGLING(oedgep->unlinkDelete(), oedgep);
@ -1369,7 +1371,7 @@ void GateVisitor::mergeAssigns() {
UINFO(6, "mergeAssigns\n");
GateMergeAssignsGraphVisitor merger{&m_graph};
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
if (GateVarVertex* const vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
merger.mergeAssignsTree(vvertexp);
}
}
@ -1382,7 +1384,7 @@ void GateVisitor::mergeAssigns() {
class GateConcatVisitor final : public GateBaseVisitor {
private:
// STATE
AstVarScope* m_vscp = nullptr; // Varscope we're trying to find
const AstVarScope* m_vscp = nullptr; // Varscope we're trying to find
int m_offset = 0; // Current offset of varscope
int m_found_offset = 0; // Found offset of varscope
bool m_found = false; // Offset found
@ -1432,8 +1434,8 @@ public:
class GateClkDecompState final {
public:
int m_offset;
AstVarScope* m_last_vsp;
const int m_offset;
AstVarScope* const m_last_vsp;
GateClkDecompState(int offset, AstVarScope* vsp)
: m_offset{offset}
, m_last_vsp{vsp} {}
@ -1453,14 +1455,14 @@ private:
virtual VNUser visit(GateVarVertex* vvertexp, VNUser vu) override {
// Check that we haven't been here before
AstVarScope* vsp = vvertexp->varScp();
AstVarScope* const vsp = vvertexp->varScp();
if (vsp->user2SetOnce()) return VNUser(0);
UINFO(9, "CLK DECOMP Var - " << vvertexp << " : " << vsp << endl);
if (vsp->varp()->width() > 1) {
m_seen_clk_vectors++;
m_total_seen_clk_vectors++;
}
GateClkDecompState* currState = reinterpret_cast<GateClkDecompState*>(vu.c());
const GateClkDecompState* const currState = reinterpret_cast<GateClkDecompState*>(vu.c());
GateClkDecompState nextState(currState->m_offset, vsp);
vvertexp->iterateCurrentOutEdges(*this, VNUser(&nextState));
if (vsp->varp()->width() > 1) --m_seen_clk_vectors;
@ -1469,13 +1471,13 @@ private:
}
virtual VNUser visit(GateLogicVertex* lvertexp, VNUser vu) override {
GateClkDecompState* currState = reinterpret_cast<GateClkDecompState*>(vu.c());
const GateClkDecompState* const currState = reinterpret_cast<GateClkDecompState*>(vu.c());
int clk_offset = currState->m_offset;
if (const AstAssignW* assignp = VN_CAST(lvertexp->nodep(), AssignW)) {
if (const AstAssignW* const assignp = VN_CAST(lvertexp->nodep(), AssignW)) {
UINFO(9, "CLK DECOMP Logic (off = " << clk_offset << ") - " << lvertexp << " : "
<< m_clk_vsp << endl);
// RHS
if (AstSel* rselp = VN_CAST(assignp->rhsp(), Sel)) {
if (const AstSel* const rselp = VN_CAST(assignp->rhsp(), Sel)) {
if (VN_IS(rselp->lsbp(), Const) && VN_IS(rselp->widthp(), Const)) {
if (clk_offset < rselp->lsbConst() || clk_offset > rselp->msbConst()) {
UINFO(9, "CLK DECOMP Sel [ " << rselp->msbConst() << " : "
@ -1487,7 +1489,7 @@ private:
} else {
return VNUser(0);
}
} else if (AstConcat* catp = VN_CAST(assignp->rhsp(), Concat)) {
} else if (AstConcat* const catp = VN_CAST(assignp->rhsp(), Concat)) {
UINFO(9, "CLK DECOMP Concat searching - " << assignp->lhsp() << endl);
int concat_offset;
if (!m_concat_visitor.concatOffset(catp, currState->m_last_vsp,
@ -1501,13 +1503,13 @@ private:
return VNUser(0);
}
// LHS
if (const AstSel* lselp = VN_CAST(assignp->lhsp(), Sel)) {
if (const AstSel* const lselp = VN_CAST(assignp->lhsp(), Sel)) {
if (VN_IS(lselp->lsbp(), Const) && VN_IS(lselp->widthp(), Const)) {
clk_offset += lselp->lsbConst();
} else {
return VNUser(0);
}
} else if (const AstVarRef* vrp = VN_CAST(assignp->lhsp(), VarRef)) {
} else if (const AstVarRef* const vrp = VN_CAST(assignp->lhsp(), VarRef)) {
if (vrp->dtypep()->width() == 1 && m_seen_clk_vectors) {
if (clk_offset != 0) {
UINFO(9, "Should only make it here with clk_offset = 0" << endl);
@ -1515,9 +1517,9 @@ private:
}
UINFO(9, "CLK DECOMP Connecting - " << assignp->lhsp() << endl);
UINFO(9, " to - " << m_clk_vsp << endl);
AstNode* rhsp = assignp->rhsp();
AstNode* const rhsp = assignp->rhsp();
rhsp->replaceWith(new AstVarRef(rhsp->fileline(), m_clk_vsp, VAccess::READ));
while (V3GraphEdge* edgep = lvertexp->inBeginp()) {
while (V3GraphEdge* const edgep = lvertexp->inBeginp()) {
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
}
new V3GraphEdge(m_graphp, m_clk_vvertexp, lvertexp, 1);
@ -1555,8 +1557,8 @@ void GateVisitor::decomposeClkVectors() {
AstNode::user2ClearTree();
GateClkDecompGraphVisitor decomposer{&m_graph};
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
if (GateVarVertex* vertp = dynamic_cast<GateVarVertex*>(itp)) {
AstVarScope* vsp = vertp->varScp();
if (GateVarVertex* const vertp = dynamic_cast<GateVarVertex*>(itp)) {
const AstVarScope* const vsp = vertp->varScp();
if (vsp->varp()->attrClocker() == VVarAttrClocker::CLOCKER_YES) {
if (vsp->varp()->width() > 1) {
UINFO(9, "Clocker > 1 bit, not decomposing: " << vsp << endl);
@ -1576,9 +1578,9 @@ class GateDeassignVisitor final : public GateBaseVisitor {
private:
// VISITORS
virtual void visit(AstVarScope* nodep) override {
if (AstNodeAssign* assp = VN_CAST(nodep->valuep(), NodeAssign)) {
if (AstNodeAssign* const assp = VN_CAST(nodep->valuep(), NodeAssign)) {
UINFO(5, " Removeassign " << assp << endl);
AstNode* valuep = assp->rhsp();
AstNode* const valuep = assp->rhsp();
valuep->unlinkFrBack();
assp->replaceWith(valuep);
VL_DO_DANGLING(assp->deleteTree(), assp);
@ -1601,8 +1603,8 @@ public:
void V3Gate::gateAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{
GateVisitor visitor{nodep};
GateDeassignVisitor deassign{nodep};
const GateVisitor visitor{nodep};
GateDeassignVisitor{nodep};
} // Destruct before checking
V3Global::dumpCheckGlobalTree("gate", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -43,18 +43,18 @@ private:
// Cleared on top scope
// AstVarScope::user2() -> AstVarScope*. Signal replacing activation with
// AstVarRef::user3() -> bool. Signal is replaced activation (already done)
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
const AstUser2InUse m_inuser2;
const AstUser3InUse m_inuser3;
// STATE
AstActive* m_activep = nullptr; // Inside activate statement
AstNodeModule* m_topModp; // Top module
AstScope* m_scopetopp = nullptr; // Scope under TOPSCOPE
const AstActive* m_activep = nullptr; // Inside activate statement
AstNodeModule* const m_topModp; // Top module
AstScope* const m_scopetopp = v3Global.rootp()->topScopep()->scopep(); // The top AstScope
// METHODS
AstVarScope* genInpClk(AstVarScope* vscp) {
if (vscp->user2p()) {
return VN_CAST(vscp->user2p(), VarScope);
return VN_AS(vscp->user2p(), VarScope);
} else {
// In order to create a __VinpClk* for a signal, it needs to be marked circular.
// The DPI export trigger is never marked circular by V3Order (see comments in
@ -69,18 +69,18 @@ private:
// that might have dependents scheduled earlier.
UASSERT_OBJ(vscp != v3Global.rootp()->dpiExportTriggerp(), vscp,
"DPI export trigger should not need __VinpClk");
AstVar* varp = vscp->varp();
string newvarname
AstVar* const varp = vscp->varp();
const string newvarname
= "__VinpClk__" + vscp->scopep()->nameDotless() + "__" + varp->name();
// Create: VARREF(inpclk)
// ...
// ASSIGN(VARREF(inpclk), VARREF(var))
AstVar* newvarp
AstVar* const newvarp
= new AstVar(varp->fileline(), AstVarType::MODULETEMP, newvarname, varp);
m_topModp->addStmtp(newvarp);
AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp);
AstVarScope* const newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp);
m_scopetopp->addVarp(newvscp);
AstAssign* asninitp = new AstAssign(
AstAssign* const asninitp = new AstAssign(
vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, VAccess::WRITE),
new AstVarRef(vscp->fileline(), vscp, VAccess::READ));
m_scopetopp->addFinalClkp(asninitp);
@ -93,25 +93,21 @@ private:
// VISITORS
virtual void visit(AstTopScope* nodep) override {
AstNode::user2ClearTree(); // user2p() used on entire tree
AstScope* scopep = nodep->scopep();
UASSERT_OBJ(scopep, nodep, "No scope found on top level");
m_scopetopp = scopep;
iterateChildren(nodep);
}
//----
virtual void visit(AstVarRef* nodep) override {
// Consumption/generation of a variable,
AstVarScope* vscp = nodep->varScopep();
AstVarScope* const vscp = nodep->varScopep();
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
if (m_activep && !nodep->user3()) {
nodep->user3(true);
if (vscp->isCircular()) {
UINFO(8, " VarActReplace " << nodep << endl);
// Replace with the new variable
AstVarScope* newvscp = genInpClk(vscp);
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->access());
AstVarScope* const newvscp = genInpClk(vscp);
AstVarRef* const newrefp
= new AstVarRef(nodep->fileline(), newvscp, nodep->access());
nodep->replaceWith(newrefp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
@ -120,7 +116,7 @@ private:
virtual void visit(AstActive* nodep) override {
m_activep = nodep;
UASSERT_OBJ(nodep->sensesp(), nodep, "Unlinked");
iterateChildren(nodep->sensesp()); // iterateAndNext?
iterate(nodep->sensesp());
m_activep = nullptr;
iterateChildren(nodep);
}
@ -145,12 +141,12 @@ private:
// NODE STATE
// Cleared on top scope
// AstVarScope::user() -> bool. Set when the var has been used as clock
AstUser1InUse m_inuser1;
const AstUser1InUse m_inuser1;
// STATE
bool m_tracingCall = false; // Iterating into a call to a cfunc
AstActive* m_activep = nullptr; // Inside activate statement
AstNodeAssign* m_assignp = nullptr; // Inside assigndly statement
const AstActive* m_activep = nullptr; // Inside activate statement
const AstNodeAssign* m_assignp = nullptr; // Inside assigndly statement
AstNodeModule* m_topModp = nullptr; // Top module
// VISITORS
@ -160,7 +156,7 @@ private:
{
// Make the new clock signals and replace any activate references
// See rename, it does some AstNode::userClearTree()'s
GenClkRenameVisitor visitor{nodep, m_topModp};
GenClkRenameVisitor{nodep, m_topModp};
}
}
virtual void visit(AstNodeModule* nodep) override {
@ -192,7 +188,7 @@ private:
virtual void visit(AstVarRef* nodep) override {
// Consumption/generation of a variable,
AstVarScope* vscp = nodep->varScopep();
AstVarScope* const vscp = nodep->varScopep();
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
if (m_activep) {
UINFO(8, " VarAct " << nodep << endl);
@ -215,7 +211,7 @@ private:
UINFO(8, "ACTIVE " << nodep << endl);
m_activep = nodep;
UASSERT_OBJ(nodep->sensesp(), nodep, "Unlinked");
iterateChildren(nodep->sensesp()); // iterateAndNext?
iterate(nodep->sensesp());
m_activep = nullptr;
iterateChildren(nodep);
}
@ -235,6 +231,6 @@ public:
void V3GenClk::genClkAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ GenClkReadVisitor visitor{nodep}; } // Destruct before checking
{ GenClkReadVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("genclk", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
}

View File

@ -46,7 +46,7 @@ void V3Global::checkTree() const { rootp()->checkTree(); }
void V3Global::readFiles() {
// NODE STATE
// AstNode::user4p() // VSymEnt* Package and typedef symbol names
AstUser4InUse inuser4;
const AstUser4InUse inuser4;
VInFilter filter(v3Global.opt.pipeFilter());
V3ParseSym parseSyms(v3Global.rootp()); // Symbol table must be common across all parsing

View File

@ -327,7 +327,7 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const {
// List of all possible subgraphs
std::multimap<std::string, V3GraphVertex*> subgraphs;
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
string vertexSubgraph
const string vertexSubgraph
= (colorAsSubgraph && vertexp->color()) ? cvtToStr(vertexp->color()) : "";
subgraphs.emplace(vertexSubgraph, vertexp);
}
@ -341,7 +341,7 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const {
string subgr;
for (auto it = subgraphs.cbegin(); it != subgraphs.cend(); ++it) {
const string vertexSubgraph = it->first;
V3GraphVertex* vertexp = it->second;
const V3GraphVertex* vertexp = it->second;
numMap[vertexp] = n;
if (subgr != vertexSubgraph) {
if (subgr != "") *logp << "\t};\n";

View File

@ -88,10 +88,6 @@ protected:
friend class V3GraphEdge;
friend class GraphAcyc;
// METHODS
void acyclicDFS();
void acyclicDFSIterate(V3GraphVertex* vertexp, int depth, uint32_t currentRank);
void acyclicCut();
void acyclicLoop(V3GraphVertex* vertexp, int depth);
double orderDFSIterate(V3GraphVertex* vertexp);
void dumpEdge(std::ostream& os, V3GraphVertex* vertexp, V3GraphEdge* edgep);
void verticesUnlink() { m_vertices.reset(); }

View File

@ -58,7 +58,7 @@ class GraphAcycEdge final : public V3GraphEdge {
private:
using OrigEdgeList = std::list<V3GraphEdge*>; // List of orig edges, see also GraphAcyc's decl
V3GraphEdge* origEdgep() const {
OrigEdgeList* oEListp = static_cast<OrigEdgeList*>(userp());
const OrigEdgeList* const oEListp = static_cast<OrigEdgeList*>(userp());
if (!oEListp) v3fatalSrc("No original edge associated with acyc edge " << this);
return (oEListp->front());
}
@ -102,7 +102,8 @@ private:
V3Graph m_breakGraph; // Graph with only breakable edges represented
V3List<GraphAcycVertex*> m_work; // List of vertices with optimization work left
std::vector<OrigEdgeList*> m_origEdgeDelp; // List of deletions to do when done
V3EdgeFuncP m_origEdgeFuncp; // Function that says we follow this edge (in original graph)
const V3EdgeFuncP
m_origEdgeFuncp; // Function that says we follow this edge (in original graph)
uint32_t m_placeStep = 0; // Number that user() must be equal to to indicate processing
static int debug() { return V3Graph::debug(); }
@ -127,8 +128,8 @@ private:
}
V3GraphEdge* edgeFromEdge(V3GraphEdge* oldedgep, V3GraphVertex* fromp, V3GraphVertex* top) {
// Make new breakGraph edge, with old edge as a template
GraphAcycEdge* newEdgep = new GraphAcycEdge(&m_breakGraph, fromp, top, oldedgep->weight(),
oldedgep->cutable());
GraphAcycEdge* const newEdgep = new GraphAcycEdge(&m_breakGraph, fromp, top,
oldedgep->weight(), oldedgep->cutable());
newEdgep->userp(oldedgep->userp()); // Keep pointer to OrigEdgeList
return newEdgep;
}
@ -137,12 +138,12 @@ private:
// Note addEdge may already have a bunch of similar linked edge representations. Yuk.
UASSERT(addEdgep, "Adding nullptr");
if (!toEdgep->userp()) {
OrigEdgeList* oep = new OrigEdgeList;
OrigEdgeList* const oep = new OrigEdgeList;
m_origEdgeDelp.push_back(oep);
toEdgep->userp(oep);
}
OrigEdgeList* oEListp = static_cast<OrigEdgeList*>(toEdgep->userp());
if (OrigEdgeList* addListp = static_cast<OrigEdgeList*>(addEdgep->userp())) {
OrigEdgeList* const oEListp = static_cast<OrigEdgeList*>(toEdgep->userp());
if (OrigEdgeList* const addListp = static_cast<OrigEdgeList*>(addEdgep->userp())) {
for (const auto& itr : *addListp) oEListp->push_back(itr);
addListp->clear(); // Done with it
} else {
@ -153,7 +154,7 @@ private:
// From the break edge, cut edges in original graph it represents
UINFO(8, why << " CUT " << breakEdgep->fromp() << endl);
breakEdgep->cut();
OrigEdgeList* oEListp = static_cast<OrigEdgeList*>(breakEdgep->userp());
const OrigEdgeList* const oEListp = static_cast<OrigEdgeList*>(breakEdgep->userp());
if (!oEListp) {
v3fatalSrc("No original edge associated with cutting edge " << breakEdgep);
}
@ -166,7 +167,7 @@ private:
}
// Work Queue
void workPush(V3GraphVertex* vertexp) {
GraphAcycVertex* avertexp = static_cast<GraphAcycVertex*>(vertexp);
GraphAcycVertex* const avertexp = static_cast<GraphAcycVertex*>(vertexp);
// Add vertex to list of nodes needing further optimization trials
if (!avertexp->m_onWorkList) {
avertexp->m_onWorkList = true;
@ -175,7 +176,7 @@ private:
}
GraphAcycVertex* workBeginp() { return m_work.begin(); }
void workPop() {
GraphAcycVertex* avertexp = workBeginp();
GraphAcycVertex* const avertexp = workBeginp();
avertexp->m_onWorkList = false;
avertexp->m_work.unlink(m_work, avertexp);
}
@ -204,7 +205,7 @@ void GraphAcyc::buildGraph(V3Graph* origGraphp) {
for (V3GraphVertex* overtexp = origGraphp->verticesBeginp(); overtexp;
overtexp = overtexp->verticesNextp()) {
if (overtexp->color()) {
GraphAcycVertex* avertexp = new GraphAcycVertex(&m_breakGraph, overtexp);
GraphAcycVertex* const avertexp = new GraphAcycVertex(&m_breakGraph, overtexp);
overtexp->userp(avertexp); // Stash so can look up later
}
}
@ -213,7 +214,7 @@ void GraphAcyc::buildGraph(V3Graph* origGraphp) {
for (V3GraphVertex* overtexp = origGraphp->verticesBeginp(); overtexp;
overtexp = overtexp->verticesNextp()) {
if (overtexp->color()) {
GraphAcycVertex* avertexp = static_cast<GraphAcycVertex*>(overtexp->userp());
GraphAcycVertex* const avertexp = static_cast<GraphAcycVertex*>(overtexp->userp());
buildGraphIterate(overtexp, avertexp);
}
}
@ -223,9 +224,10 @@ void GraphAcyc::buildGraphIterate(V3GraphVertex* overtexp, GraphAcycVertex* aver
// Make new edges
for (V3GraphEdge* edgep = overtexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
if (origFollowEdge(edgep)) { // not cut
V3GraphVertex* toVertexp = edgep->top();
const V3GraphVertex* toVertexp = edgep->top();
if (toVertexp->color()) {
GraphAcycVertex* toAVertexp = static_cast<GraphAcycVertex*>(toVertexp->userp());
GraphAcycVertex* const toAVertexp
= static_cast<GraphAcycVertex*>(toVertexp->userp());
// Replicate the old edge into the new graph
// There may be multiple edges between same pairs of vertices
V3GraphEdge* breakEdgep = new GraphAcycEdge(&m_breakGraph, avertexp, toAVertexp,
@ -266,7 +268,7 @@ void GraphAcyc::deleteMarked() {
for (V3GraphVertex *nextp, *vertexp = m_breakGraph.verticesBeginp(); vertexp;
vertexp = nextp) {
nextp = vertexp->verticesNextp();
GraphAcycVertex* avertexp = static_cast<GraphAcycVertex*>(vertexp);
GraphAcycVertex* const avertexp = static_cast<GraphAcycVertex*>(vertexp);
if (avertexp->isDelete()) {
VL_DO_DANGLING(avertexp->unlinkDelete(&m_breakGraph), avertexp);
}
@ -281,13 +283,13 @@ void GraphAcyc::simplifyNone(GraphAcycVertex* avertexp) {
UINFO(9, " SimplifyNoneRemove " << avertexp << endl);
avertexp->setDelete(); // Mark so we won't delete it twice
// Remove edges
while (V3GraphEdge* edgep = avertexp->outBeginp()) {
while (V3GraphEdge* const edgep = avertexp->outBeginp()) {
V3GraphVertex* otherVertexp = edgep->top();
// UINFO(9, " out " << otherVertexp << endl);
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
workPush(otherVertexp);
}
while (V3GraphEdge* edgep = avertexp->inBeginp()) {
while (V3GraphEdge* const edgep = avertexp->inBeginp()) {
V3GraphVertex* otherVertexp = edgep->fromp();
// UINFO(9, " in " << otherVertexp << endl);
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
@ -483,7 +485,7 @@ void GraphAcyc::placeTryEdge(V3GraphEdge* edgep) {
// Vertex::m_user begin: number indicates this edge was completed
// Try to assign ranks, presuming this edge is in place
// If we come across user()==placestep, we've detected a loop and must back out
bool loop
const bool loop
= placeIterate(static_cast<GraphAcycVertex*>(edgep->top()), edgep->fromp()->rank() + 1);
if (!loop) {
// No loop, we can keep it as uncutable

View File

@ -31,7 +31,7 @@
// Algorithms - weakly connected components
class GraphRemoveRedundant final : GraphAlg<> {
bool m_sumWeights; ///< Sum, rather then maximize weights
const bool m_sumWeights; ///< Sum, rather then maximize weights
private:
void main() {
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
@ -213,7 +213,7 @@ private:
}
void vertexIterate(V3GraphVertex* vertexp) {
uint32_t thisDfsNum = m_currentDfs++;
const uint32_t thisDfsNum = m_currentDfs++;
vertexp->user(thisDfsNum);
vertexp->color(0);
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {

View File

@ -30,8 +30,8 @@
template <class T_Graph = V3Graph> // Or sometimes const V3Graph
class GraphAlg VL_NOT_FINAL {
protected:
T_Graph* m_graphp; // Graph we're operating upon
V3EdgeFuncP m_edgeFuncp; // Function that says we follow this edge
T_Graph* const m_graphp; // Graph we're operating upon
const V3EdgeFuncP m_edgeFuncp; // Function that says we follow this edge
// CONSTRUCTORS
GraphAlg(T_Graph* graphp, V3EdgeFuncP edgeFuncp)
: m_graphp{graphp}

View File

@ -1,605 +0,0 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Graph optimizations
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2005-2021 by Wilson Snyder. This program is free software; you
// can redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include "V3Global.h"
#include "V3GraphDfa.h"
#include "V3GraphAlg.h"
#include <map>
#include <set>
#include <stack>
//######################################################################
//######################################################################
// Algorithms - find starting node
DfaVertex* DfaGraph::findStart() {
DfaVertex* startp = nullptr;
for (V3GraphVertex* vertexp = this->verticesBeginp(); vertexp;
vertexp = vertexp->verticesNextp()) {
if (DfaVertex* vvertexp = dynamic_cast<DfaVertex*>(vertexp)) {
if (vvertexp->start()) {
UASSERT_OBJ(!startp, vertexp, "Multiple start points in NFA graph");
startp = vvertexp;
}
} else {
vertexp->v3fatalSrc("Non DfaVertex in DfaGraph");
}
}
if (!startp) v3fatalSrc("No start point in NFA graph");
return startp;
}
//######################################################################
//######################################################################
// Algorithms - convert NFA to a DFA
// Uses the Subset Construction Algorithm
class GraphNfaToDfa final : GraphAlg<> {
// We have two types of nodes in one graph, NFA and DFA nodes.
// Edges from NFA to NFA come from the user, and indicate input or epsilon transitions
// Edges from DFA to NFA indicate the NFA from which that DFA was formed.
// Edges from DFA to DFA indicate a completed input transition
private:
// TYPES
using DfaStates = std::deque<DfaVertex*>;
using HashMap = std::multimap<vluint64_t, DfaVertex*>;
// MEMBERS
uint32_t m_step; // Processing step, so we can avoid clearUser all the time
HashMap m_hashMap; // Dfa Vertex for each set of NFA vertexes
#ifdef VL_CPPCHECK
static int debug() { return 9; }
#else
static int debug() { return 0; }
#endif
// METHODS
DfaGraph* graphp() { return static_cast<DfaGraph*>(m_graphp); }
static bool nfaState(V3GraphVertex* vertexp) { return vertexp->color() == 0; }
// static bool dfaState(V3GraphVertex* vertexp) { return vertexp->color()==1; }
void nextStep() { m_step++; }
bool unseenNfaThisStep(V3GraphVertex* vertexp) {
// A nfa node not already seen this processing step
return (nfaState(vertexp) && !(vertexp->user() == m_step));
}
DfaVertex* newDfaVertex(DfaVertex* nfaTemplatep = nullptr) {
DfaVertex* vertexp = new DfaVertex(graphp());
vertexp->color(1); // Mark as dfa
if (nfaTemplatep && nfaTemplatep->start()) vertexp->start(true);
if (nfaTemplatep && nfaTemplatep->accepting()) vertexp->accepting(true);
UINFO(9, " New " << vertexp << endl);
return vertexp;
}
// Hashing
static uint32_t hashVertex(V3GraphVertex* vertexp) {
union {
void* up;
struct {
uint32_t upper;
uint32_t lower;
} l;
} u;
u.l.upper = 0;
u.l.lower = 0;
u.up = vertexp;
return u.l.upper ^ u.l.lower;
}
uint32_t hashDfaOrigins(DfaVertex* dfaStatep) {
// Find the NFA states this dfa came from,
// Record a checksum, so we can search for it later by the list of nfa nodes.
// The order of the nodes is not deterministic; the hash thus must
// not depend on order of edges
uint32_t hash = 0;
// Foreach NFA state (this DFA state was formed from)
if (debug()) nextStep();
for (V3GraphEdge* dfaEdgep = dfaStatep->outBeginp(); dfaEdgep;
dfaEdgep = dfaEdgep->outNextp()) {
if (nfaState(dfaEdgep->top())) {
DfaVertex* nfaStatep = static_cast<DfaVertex*>(dfaEdgep->top());
hash ^= hashVertex(nfaStatep);
if (debug()) {
UASSERT_OBJ(nfaStatep->user() != m_step, nfaStatep,
"DFA state points to duplicate NFA state.");
nfaStatep->user(m_step);
}
}
}
return hash;
}
uint32_t hashDfaOrigins(const DfaStates& nfasWithInput) {
// Find the NFA states this dfa came from,
uint32_t hash = 0;
for (DfaVertex* nfaStatep : nfasWithInput) hash ^= hashVertex(nfaStatep);
return hash;
}
bool compareDfaOrigins(const DfaStates& nfasWithInput, DfaVertex* dfa2p) {
// Return true if the NFA nodes both DFAs came from are the same list
// Assume there are no duplicates in either input list or NFAs under dfa2
nextStep();
// Mark all input vertexes
int num1s = 0;
for (DfaVertex* nfaStatep : nfasWithInput) {
nfaStatep->user(m_step);
num1s++;
}
if (!num1s) v3fatalSrc("DFA node construction that contains no NFA states");
// Check comparison; must all be marked
// (Check all in dfa2p were in dfa1p)
int num2s = 0;
for (V3GraphEdge* dfaEdgep = dfa2p->outBeginp(); dfaEdgep;
dfaEdgep = dfaEdgep->outNextp()) {
if (nfaState(dfaEdgep->top())) {
if (dfaEdgep->top()->user() != m_step) return false;
num2s++;
}
}
// If we saw all of the nodes, then they have the same number of hits
// (Else something in dfa1p that wasn't in dfa2p)
return (num1s == num2s);
}
void insertDfaOrigins(DfaVertex* dfaStatep) {
// Record the NFA states this dfa came from
uint32_t hash = hashDfaOrigins(dfaStatep);
m_hashMap.emplace(hash, dfaStatep);
}
DfaVertex* findDfaOrigins(const DfaStates& nfasWithInput) {
// Find another DFA state which comes from the identical set of NFA states
// The order of the nodes is not deterministic; the hash thus must
// not depend on order of edges
uint32_t hash = hashDfaOrigins(nfasWithInput);
const auto eqrange = m_hashMap.equal_range(hash);
for (auto it = eqrange.first; it != eqrange.second; ++it) {
DfaVertex* testp = it->second;
if (compareDfaOrigins(nfasWithInput, testp)) {
UINFO(9, " DFA match for set: " << testp << endl);
return testp; // Identical
}
}
return nullptr; // No match
}
void findNfasWithInput(DfaVertex* dfaStatep, const DfaInput& input, DfaStates& nfasWithInput) {
// Return all NFA states, with the given input transition from
// the nfa states a given dfa state was constructed from.
nextStep();
nfasWithInput.clear(); // NFAs with given input
// Foreach NFA state (this DFA state was formed from)
for (V3GraphEdge* dfaEdgep = dfaStatep->outBeginp(); dfaEdgep;
dfaEdgep = dfaEdgep->outNextp()) {
if (nfaState(dfaEdgep->top())) {
DfaVertex* nfaStatep = static_cast<DfaVertex*>(dfaEdgep->top());
// Foreach input transition (on this nfaStatep)
for (V3GraphEdge* nfaEdgep = nfaStatep->outBeginp(); nfaEdgep;
nfaEdgep = nfaEdgep->outNextp()) {
DfaEdge* cNfaEdgep = static_cast<DfaEdge*>(nfaEdgep);
if (cNfaEdgep->input().toNodep() == input.toNodep()) {
DfaVertex* nextStatep = static_cast<DfaVertex*>(cNfaEdgep->top());
if (unseenNfaThisStep(nextStatep)) { // Not processed?
nfasWithInput.push_back(nextStatep);
nextStatep->user(m_step);
UINFO(9, " Reachable " << nextStatep << endl);
}
}
}
}
}
// Expand the nfasWithInput list to include epsilon states
// reachable by those on nfasWithInput
{
DfaStates nfasTodo = nfasWithInput;
nfasWithInput.clear(); // Now the completed list
while (!nfasTodo.empty()) {
DfaVertex* nfaStatep = nfasTodo.front();
nfasTodo.pop_front();
nfasWithInput.push_back(nfaStatep);
// Foreach epsilon-reachable (on this nfaStatep)
for (V3GraphEdge* nfaEdgep = nfaStatep->outBeginp(); nfaEdgep;
nfaEdgep = nfaEdgep->outNextp()) {
DfaEdge* cNfaEdgep = static_cast<DfaEdge*>(nfaEdgep);
if (cNfaEdgep->epsilon()) {
DfaVertex* nextStatep = static_cast<DfaVertex*>(cNfaEdgep->top());
if (unseenNfaThisStep(nextStatep)) { // Not processed?
nfasTodo.push_back(nextStatep);
nextStatep->user(m_step);
UINFO(9, " Epsilon Reachable " << nextStatep << endl);
}
}
}
}
}
}
void main() {
UINFO(5, "Dfa to Nfa conversion...\n");
// Vertex::color() begin: 1 indicates vertex on DFA graph, 0=NFA graph
m_graphp->clearColors();
// Vertex::m_user begin: # indicates processed this m_step number
m_graphp->userClearVertices();
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("dfa_nfa");
// Find NFA start
DfaVertex* nfaStartp = graphp()->findStart();
// Create new DFA State (start state) from the NFA states
DfaVertex* dfaStartp = newDfaVertex(nfaStartp);
DfaStates dfaUnprocps; // Unprocessed DFA nodes
dfaUnprocps.push_back(dfaStartp);
UINFO(5, "Starting state conversion...\n");
// Form DFA starting state from epsilon closure of NFA start
nextStep();
DfaStates workps;
workps.push_back(nfaStartp);
while (!workps.empty()) { // While work
DfaVertex* nfaStatep = workps.back();
workps.pop_back();
// UINFO(9," Processing "<<nfaStatep<<endl);
nfaStatep->user(m_step); // Mark as processed
// Add a edge so we can find NFAs from a given DFA.
// The NFA will never see this edge, because we only look at TO edges.
new DfaEdge(graphp(), dfaStartp, nfaStatep, DfaEdge::NA());
// Find epsilon closure of this nfa node, and destinations to work list
for (V3GraphEdge* nfaEdgep = nfaStatep->outBeginp(); nfaEdgep;
nfaEdgep = nfaEdgep->outNextp()) {
DfaEdge* cNfaEdgep = static_cast<DfaEdge*>(nfaEdgep);
DfaVertex* ecNfaStatep = static_cast<DfaVertex*>(nfaEdgep->top());
// UINFO(9," Consider "<<nfaEdgep->top()<<" EP "<<cNfaEdgep->epsilon()<<endl);
if (cNfaEdgep->epsilon() && unseenNfaThisStep(ecNfaStatep)) { // Not processed?
workps.push_back(ecNfaStatep);
}
}
}
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("dfa_start");
insertDfaOrigins(dfaStartp);
int i = 0;
UINFO(5, "Main state conversion...\n");
while (!dfaUnprocps.empty()) {
DfaVertex* dfaStatep = dfaUnprocps.back();
dfaUnprocps.pop_back();
UINFO(9, " On dfaState " << dfaStatep << endl);
// From this dfaState, what corresponding nfaStates have what inputs?
std::unordered_set<int> inputs;
// Foreach NFA state (this DFA state was formed from)
for (V3GraphEdge* dfaEdgep = dfaStatep->outBeginp(); dfaEdgep;
dfaEdgep = dfaEdgep->outNextp()) {
if (nfaState(dfaEdgep->top())) {
DfaVertex* nfaStatep = static_cast<DfaVertex*>(dfaEdgep->top());
// Foreach input on this nfaStatep
for (V3GraphEdge* nfaEdgep = nfaStatep->outBeginp(); nfaEdgep;
nfaEdgep = nfaEdgep->outNextp()) {
DfaEdge* cNfaEdgep = static_cast<DfaEdge*>(nfaEdgep);
if (!cNfaEdgep->epsilon()) {
if (inputs.find(cNfaEdgep->input().toInt()) == inputs.end()) {
inputs.insert(cNfaEdgep->input().toInt());
UINFO(9, " Input to " << dfaStatep << " is "
<< (cNfaEdgep->input().toInt()) << " via "
<< nfaStatep << endl);
}
}
}
}
}
// Foreach input state (NFA inputs of this DFA state)
for (int inIt : inputs) {
const DfaInput input = inIt;
UINFO(9, " ===" << ++i << "=======================\n");
UINFO(9, " On input " << cvtToHex(input.toNodep()) << endl);
// Find all states reachable for given input
DfaStates nfasWithInput;
findNfasWithInput(dfaStatep, input, nfasWithInput /*ref*/);
// nfasWithInput now maps to the DFA we want a transition to.
// Does a DFA already exist with this, and only this subset of NFA's?
DfaVertex* toDfaStatep = findDfaOrigins(nfasWithInput);
if (!toDfaStatep) {
// Doesn't exist, make new dfa state corresponding to this one,
toDfaStatep = newDfaVertex();
dfaUnprocps.push_back(toDfaStatep); // Add to process list
// Track what nfa's point to it.
for (DfaStates::const_iterator nfaIt = nfasWithInput.begin();
nfaIt != nfasWithInput.end(); ++nfaIt) {
UINFO(9, " NewContainsNfa " << *nfaIt << endl);
new DfaEdge(graphp(), toDfaStatep, *nfaIt, DfaEdge::NA());
if ((*nfaIt)->accepting()) toDfaStatep->accepting(true);
}
insertDfaOrigins(toDfaStatep);
}
// Add input transition
new DfaEdge(graphp(), dfaStatep, toDfaStatep, input);
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("step");
}
}
// Remove old NFA states
UINFO(5, "Removing NFA states...\n");
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("dfa_withnfa");
for (V3GraphVertex *nextp, *vertexp = m_graphp->verticesBeginp(); vertexp;
vertexp = nextp) {
nextp = vertexp->verticesNextp();
if (nfaState(vertexp)) VL_DO_DANGLING(vertexp->unlinkDelete(m_graphp), vertexp);
}
UINFO(5, "Done.\n");
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("dfa_done");
}
public:
GraphNfaToDfa(V3Graph* graphp, V3EdgeFuncP edgeFuncp)
: GraphAlg<>{graphp, edgeFuncp} {
m_step = 0;
main();
}
~GraphNfaToDfa() = default;
};
void DfaGraph::nfaToDfa() { GraphNfaToDfa(this, &V3GraphEdge::followAlwaysTrue); }
//######################################################################
//######################################################################
// Algorithms - optimize a DFA structure
//
// Scan the DFA, cleaning up trailing states.
class DfaGraphReduce final : GraphAlg<> {
private:
// METHODS
#ifdef VL_CPPCHECK
static int debug() { return 9; }
#else
static int debug() { return 0; }
#endif
DfaGraph* graphp() { return static_cast<DfaGraph*>(m_graphp); }
bool isDead(DfaVertex* vertexp) {
// A state is dead if not accepting, and goes nowhere
if (vertexp->accepting() || vertexp->start()) return false;
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
if (edgep->top() != vertexp) return false;
}
return true;
}
void optimize_accepting_out() {
// Delete outbound edges from accepting states
// (As once we've accepted, we no longer care about anything else.)
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
vertexp = vertexp->verticesNextp()) {
if (DfaVertex* vvertexp = dynamic_cast<DfaVertex*>(vertexp)) {
if (vvertexp->accepting()) {
for (V3GraphEdge *nextp, *edgep = vertexp->outBeginp(); edgep; edgep = nextp) {
nextp = edgep->outNextp();
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
}
}
}
}
}
void optimize_orphans() {
// Remove states that don't come from start
// Presumably the previous optimization orphaned them.
// Vertex::m_user begin: 1 indicates on the work list, 2 processed
// (Otherwise we might have nodes on the list twice, and reference after deleting them.)
m_graphp->userClearVertices();
DfaVertex* startp = graphp()->findStart();
std::stack<V3GraphVertex*> workps;
workps.push(startp);
// Mark all nodes connected to start
while (!workps.empty()) {
V3GraphVertex* vertexp = workps.top();
workps.pop();
vertexp->user(2); // Processed
// Add nodes from here to the work list
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
V3GraphVertex* tovertexp = edgep->top();
if (!tovertexp->user()) {
workps.push(tovertexp);
tovertexp->user(1);
}
}
}
// Delete all nodes not connected
for (V3GraphVertex *nextp, *vertexp = m_graphp->verticesBeginp(); vertexp;
vertexp = nextp) {
nextp = vertexp->verticesNextp();
if (!vertexp->user()) VL_DO_DANGLING(vertexp->unlinkDelete(m_graphp), vertexp);
}
}
void optimize_no_outbound() {
// Non-accepting states with no outbound transitions may be
// deleted. Then, any arcs feeding those states, and perhaps those
// states...
// Vertex::m_user begin: 1 indicates on the work list
// (Otherwise we might have nodes on the list twice, and reference after deleting them.)
m_graphp->userClearVertices();
// Find all dead vertexes
std::stack<DfaVertex*> workps;
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
vertexp = vertexp->verticesNextp()) {
if (DfaVertex* vvertexp = dynamic_cast<DfaVertex*>(vertexp)) {
workps.push(vvertexp);
vertexp->user(1);
} else {
// If ever remove this, need dyn cast below
vertexp->v3fatalSrc("Non DfaVertex in dfa graph");
}
}
// While deadness... Delete and find new dead nodes.
while (!workps.empty()) {
DfaVertex* vertexp = workps.top();
workps.pop();
vertexp->user(0);
if (isDead(vertexp)) {
// Add nodes that go here to the work list
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
DfaVertex* fromvertexp = static_cast<DfaVertex*>(edgep->fromp());
if (fromvertexp != vertexp && !fromvertexp->user()) {
workps.push(fromvertexp);
fromvertexp->user(1);
}
}
// Transitions to this state removed by the unlink function
VL_DO_DANGLING(vertexp->unlinkDelete(m_graphp), vertexp);
}
}
}
public:
DfaGraphReduce(V3Graph* graphp, V3EdgeFuncP edgeFuncp)
: GraphAlg<>{graphp, edgeFuncp} {
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("opt_in");
optimize_accepting_out();
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("opt_acc");
optimize_orphans();
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("opt_orph");
optimize_no_outbound();
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("opt_noout");
}
~DfaGraphReduce() = default;
};
void DfaGraph::dfaReduce() { DfaGraphReduce(this, &V3GraphEdge::followAlwaysTrue); }
//######################################################################
//######################################################################
// Algorithms - complement a DFA
//
// The traditional algorithm is to make a rejecting state, add edges to
// reject from all missing values, then swap accept and reject. Rather
// than swap at the end, it's faster if we swap up front, then do the edge
// changes.
//
// 1. Since we didn't log rejecting states, make a temp state (this will be
// the old accept, and new reject).
//
// 2. All vertexes except start/accept get edges to NEW accept for any
// non-existing case. Weedely we don't have a nice way of representing
// this so we just create a edge for each case and mark it "complemented."
//
// 3. Delete temp vertex (old accept/new reject) and related edges.
// The user's old accept is now the new accept. This is important as
// we want the virtual type of it to be intact.
class DfaGraphComplement final : GraphAlg<> {
private:
// MEMBERS
DfaVertex* m_tempNewerReject;
// METHODS
static int debug() { return 9; }
DfaGraph* graphp() { return static_cast<DfaGraph*>(m_graphp); }
void add_complement_edges() {
// Find accepting vertex
DfaVertex* acceptp = nullptr;
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
vertexp = vertexp->verticesNextp()) {
if (DfaVertex* vvertexp = dynamic_cast<DfaVertex*>(vertexp)) {
if (vvertexp->accepting()) {
acceptp = vvertexp;
break;
}
}
}
if (!acceptp) v3fatalSrc("No accepting vertex in DFA");
// Remap edges
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
vertexp = vertexp->verticesNextp()) {
if (DfaVertex* vvertexp = dynamic_cast<DfaVertex*>(vertexp)) {
// UINFO(9, " on vertex "<<vvertexp->name()<<endl);
if (!vvertexp->accepting() && vvertexp != m_tempNewerReject) {
for (V3GraphEdge *nextp, *edgep = vertexp->outBeginp(); edgep; edgep = nextp) {
nextp = edgep->outNextp();
if (!edgep->user()) { // Not processed
// Old edges to accept now go to new reject
DfaEdge* vedgep = static_cast<DfaEdge*>(edgep);
DfaVertex* tovertexp = static_cast<DfaVertex*>(edgep->top());
if (tovertexp->accepting()) {
new DfaEdge(graphp(), vvertexp, m_tempNewerReject, vedgep);
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
}
// NOT of all values goes to accept
// We make a edge for each value to OR, IE
// edge(complemented,a) edge(complemented,b) means !(a | b)
if (!tovertexp->accepting()) {
// Note we must include edges moved above to reject
DfaEdge* newp = new DfaEdge(graphp(), vvertexp, acceptp, vedgep);
newp->complement(!newp->complement());
newp->user(1);
}
}
}
}
}
}
}
public:
DfaGraphComplement(V3Graph* dfagraphp, V3EdgeFuncP edgeFuncp)
: GraphAlg<>{dfagraphp, edgeFuncp} {
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("comp_in");
// Vertex::m_user begin: 1 indicates new edge, no more processing
m_graphp->userClearEdges();
m_tempNewerReject = new DfaVertex(graphp());
add_complement_edges();
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("comp_preswap");
VL_DO_CLEAR(m_tempNewerReject->unlinkDelete(graphp()), m_tempNewerReject = nullptr);
if (debug() >= 6) m_graphp->dumpDotFilePrefixed("comp_out");
}
~DfaGraphComplement() = default;
VL_UNCOPYABLE(DfaGraphComplement);
};
void DfaGraph::dfaComplement() { DfaGraphComplement(this, &V3GraphEdge::followAlwaysTrue); }

View File

@ -1,152 +0,0 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Graph automata base class
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2003-2021 by Wilson Snyder. This program is free software; you
// can redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************
#ifndef VERILATOR_V3GRAPHDFA_H_
#define VERILATOR_V3GRAPHDFA_H_
#include "config_build.h"
#include "verilatedos.h"
#include "V3Ast.h" // for VNUser
#include "V3Global.h"
#include "V3Graph.h"
class DfaGraph;
class DfaVertex;
class DfaEdge;
//=============================================================================
// NFA/DFA Graphs
/// The NFA graph consists of:
/// DfaVertex(START) The starting point
/// DfaVertex() Interior states
/// DfaVertex(ACCEPT) The completion point
///
/// Transitions include a list of all inputs (arbitrary user pointers),
/// or epsilon, represented as a empty list of inputs.
///
/// We're only looking for matches, so the only accepting states are
/// at the end of the transformations. (If we want the complement, we
/// call complement and the algorithm makes a REJECT state, then flips
/// accept and reject for you.)
///
/// Common transforms:
///
/// "*": DfaVertex(START) --> [epsilon] -->DfaVertex(ACCEPT)
///
/// "L": ...->[ON_L]-->DfaVtx-->[epsilon]-->DfaVtx(ACCEPT)
///
/// "LR": ...->[ON_L]-->DfaVtx-->[epsilon]-->DfaVtx(ACCEPT)
/// ->[ON_R]-->DfaVtx-->[epsilon]-/
///
/// "L|R": ...->DfaVtx-->[epsilon]-->DfaVtx-->[ON_L]-->DfaVtx()->[epsilon]-->DfaVtx(ACCEPT)
/// \->[epsilon]-->DfaVtx-->[ON_R]-->DfaVtx()->[epsilon]-/
///
/// "L*": ...->DfaVtx-->[epsilon]-->DfaVtx-->[ON_L]-->DfaVtx()->[epsilon]-->DfaVtx(ACCEPT)
/// | ^\----[epsilon]<-------/ |
/// \->[epsilon]-----------------------------------------/
class DfaGraph final : public V3Graph {
public:
// CONSTRUCTORS
DfaGraph() = default;
virtual ~DfaGraph() override = default;
// METHODS
/// Find start node
DfaVertex* findStart();
/// Convert automata: NFA to DFA
void nfaToDfa();
/// Simplify a DFA automata
void dfaReduce();
/// Complement result (must already be dfa)
void dfaComplement();
};
//=============================================================================
// Vertex
class DfaVertex VL_NOT_FINAL : public V3GraphVertex {
// Each DFA state is captured in this vertex.
// Start and accepting are members, rather than the more intuitive
// subclasses, as subclassing them would make it harder to inherit from here.
bool m_start; // Start state
bool m_accepting; // Accepting state?
public:
// CONSTRUCTORS
explicit DfaVertex(DfaGraph* graphp, bool start = false, bool accepting = false)
: V3GraphVertex{graphp}
, m_start{start}
, m_accepting{accepting} {}
using V3GraphVertex::clone; // We are overriding, not overloading clone(V3Graph*)
virtual DfaVertex* clone(DfaGraph* graphp) {
return new DfaVertex(graphp, start(), accepting());
}
virtual ~DfaVertex() override = default;
// ACCESSORS
virtual string dotShape() const override { return (accepting() ? "doublecircle" : ""); }
virtual string dotColor() const override {
return start() ? "blue" : (color() ? "red" : "black");
}
bool start() const { return m_start; }
void start(bool flag) { m_start = flag; }
bool accepting() const { return m_accepting; }
void accepting(bool flag) { m_accepting = flag; }
};
//============================================================================
/// Abstract type indicating a specific "input" to the NFA
/// DFA assumes each .toInt() is unique
using DfaInput = VNUser;
//============================================================================
// Edge types
class DfaEdge final : public V3GraphEdge {
DfaInput m_input;
bool m_complement; // Invert value when doing compare
public:
static DfaInput EPSILON() { return VNUser::fromInt(0); }
static DfaInput NA() { return VNUser::fromInt(1); } // as in not-applicable
// CONSTRUCTORS
DfaEdge(DfaGraph* graphp, DfaVertex* fromp, DfaVertex* top, const DfaInput& input)
: V3GraphEdge{graphp, fromp, top, 1}
, m_input{input}
, m_complement{false} {}
DfaEdge(DfaGraph* graphp, DfaVertex* fromp, DfaVertex* top, const DfaEdge* copyfrom)
: V3GraphEdge{graphp, fromp, top, copyfrom->weight()}
, m_input{copyfrom->input()}
, m_complement{copyfrom->complement()} {}
virtual ~DfaEdge() override = default;
// METHODS
virtual string dotColor() const override {
return (na() ? "yellow" : epsilon() ? "green" : "black");
}
virtual string dotLabel() const override {
return (na() ? ""
: epsilon() ? "e"
: complement() ? ("not " + cvtToStr(input().toInt()))
: cvtToStr(input().toInt()));
}
virtual string dotStyle() const override { return (na() || cutable()) ? "dashed" : ""; }
bool epsilon() const { return input().toInt() == EPSILON().toInt(); }
bool na() const { return input().toInt() == NA().toInt(); }
bool complement() const { return m_complement; }
void complement(bool value) { m_complement = value; }
DfaInput input() const { return m_input; }
};
//============================================================================
#endif // Guard

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