Internals: Add lcov code coverage markers.

This commit is contained in:
Wilson Snyder 2019-06-30 22:37:03 -04:00
parent ac43e7322b
commit 01ef7122e9
29 changed files with 388 additions and 85 deletions

View File

@ -496,8 +496,9 @@ clean mostlyclean distclean maintainer-clean::
rm -f *.pg *.pgs *.toc *.tp *.tps *.vr *.vrs *.idx
rm -f *.ev *.evs *.ov *.ovs *.cv *.cvs *.ma *.mas
rm -f *.tex
rm -rf test_*/obj_dir
rm -rf examples/*/obj_dir examples/*/logs
rm -rf test_*/obj_dir
rm -rf nodist/obj_dir
distclean maintainer-clean::
rm -f *.info* *.1 $(INFOS)

View File

@ -1093,8 +1093,8 @@ IData VL_FGETS_IXI(int obits, void* destp, IData fpi) VL_MT_SAFE {
IData bytes = VL_BYTES_I(obits);
char buffer[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1];
// V3Emit has static check that bytes < VL_TO_STRING_MAX_WORDS, but be safe
if (VL_UNLIKELY(bytes > VL_TO_STRING_MAX_WORDS*VL_WORDSIZE)) {
VL_FATAL_MT(__FILE__, __LINE__, "", "Internal: fgets buffer overrun");
if (VL_UNCOVERABLE(bytes > VL_TO_STRING_MAX_WORDS*VL_WORDSIZE)) {
VL_FATAL_MT(__FILE__, __LINE__, "", "Internal: fgets buffer overrun"); // LCOV_EXCL_LINE
}
// We don't use fgets, as we must read \0s.
@ -1317,7 +1317,7 @@ const char* memhFormat(int nBits) {
case 5: VL_SNPRINTF(buf, 32, "%%06x"); break;
case 6: VL_SNPRINTF(buf, 32, "%%07x"); break;
case 7: VL_SNPRINTF(buf, 32, "%%08x"); break;
default: assert(false); break;
default: assert(false); break; // LCOV_EXCL_LINE
}
return buf;
}
@ -1842,9 +1842,9 @@ void Verilated::flushCb(VerilatedVoidCb cb) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex);
if (s_flushCb == cb) {} // Ok - don't duplicate
else if (!s_flushCb) { s_flushCb=cb; }
else {
else { // LCOV_EXCL_LINE
// Someday we may allow multiple callbacks ala atexit(), but until then
VL_FATAL_MT("unknown", 0, "",
VL_FATAL_MT("unknown", 0, "", // LCOV_EXCL_LINE
"Verilated::flushCb called twice with different callbacks");
}
}
@ -2136,8 +2136,8 @@ void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) VL_
// Alternative is to dynamically stretch the array, which is more code, and slower.
if (funcnum >= m_funcnumMax) { m_funcnumMax = funcnum+1; }
} else {
if (VL_UNLIKELY(funcnum >= m_funcnumMax)) {
VL_FATAL_MT(__FILE__, __LINE__, "",
if (VL_UNCOVERABLE(funcnum >= m_funcnumMax)) {
VL_FATAL_MT(__FILE__, __LINE__, "", // LCOV_EXCL_LINE
"Internal: Bad funcnum vs. pre-finalize maximum");
}
if (VL_UNLIKELY(!m_callbacksp)) { // First allocation

View File

@ -189,8 +189,8 @@ public:
// METHODS
/// Check that the current thread ID is the same as the construction thread ID
void check() VL_MT_UNSAFE_ONE {
if (!VL_LIKELY(m_threadid == VL_THREAD_ID())) {
fatal_different();
if (VL_UNCOVERABLE(m_threadid != VL_THREAD_ID())) {
fatal_different(); // LCOV_EXCL_LINE
}
}
static void fatal_different() VL_MT_SAFE;

View File

@ -221,8 +221,7 @@ void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed) {
eit->m_cpu,
thread_id);
break;
default: assert(false);
break;
default: assert(false); break; // LCOV_EXCL_LINE
}
}
}

View File

@ -74,7 +74,7 @@ public:
// We reserve word zero for the next pointer, as that's safer in case a
// dangling reference to the original remains around.
static const size_t chunk = 96;
if (VL_UNLIKELY(size>chunk)) VL_FATAL_MT(__FILE__, __LINE__, "", "increase chunk");
if (VL_UNCOVERABLE(size>chunk)) VL_FATAL_MT(__FILE__, __LINE__, "", "increase chunk");
if (VL_LIKELY(t_freeHead)) {
vluint8_t* newp = t_freeHead;
t_freeHead = *((vluint8_t**)newp);
@ -348,7 +348,7 @@ public:
varop->createPrevDatap();
}
}
if (VL_UNLIKELY(vop->reason() >= CB_ENUM_MAX_VALUE)) {
if (VL_UNCOVERABLE(vop->reason() >= CB_ENUM_MAX_VALUE)) {
VL_FATAL_MT(__FILE__, __LINE__, "", "vpi bb reason too large");
}
s_s.m_cbObjLists[vop->reason()].push_back(vop);
@ -1255,7 +1255,7 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
return;
case VLVT_WDATA: {
int words = VL_WORDS_I(vop->varp()->packed().elements());
if (VL_UNLIKELY(words >= VL_MULS_MAX_WORDS)) {
if (VL_UNCOVERABLE(words >= VL_MULS_MAX_WORDS)) {
VL_FATAL_MT(__FILE__, __LINE__, "",
"vpi_get_value with more than VL_MULS_MAX_WORDS; increase and recompile");
}

View File

@ -110,6 +110,7 @@
# define VL_LIKELY(x) (!!(x)) ///< Boolean expression more often true than false
# define VL_UNLIKELY(x) (!!(x)) ///< Boolean expression more often false than true
#endif
#define VL_UNCOVERABLE(x) VL_UNLIKELY(x) ///< Boolean expression never hit by users (no coverage)
#ifndef VL_UNREACHABLE
# define VL_UNREACHABLE ///< Point that may never be reached
#endif

260
nodist/code_coverage Executable file
View File

@ -0,0 +1,260 @@
#!/usr/bin/perl -w
# See copyright, etc in below POD section.
######################################################################
use Cwd;
use File::Copy qw(cp);
use File::Path qw(mkpath);
use Getopt::Long;
use IO::File;
use Pod::Usage;
use strict;
use vars qw($Debug);
our $Exclude_Line_Regexp;
our @Remove_Sources;
our @Source_Globs;
#======================================================================
# main
our $Opt_Stage = 0;
autoflush STDOUT 1;
autoflush STDERR 1;
Getopt::Long::config("no_auto_abbrev");
if (! GetOptions(
"debug" => sub { $Debug = 1; },
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
"stage=i" => \$Opt_Stage,
)) {
die "%Error: Bad usage, try 'install_test --help'\n";
}
test();
exit(0);
#######################################################################
sub test {
-r "nodist/code_coverage.dat" or die "%Error: Run from the top of the verilator kit,";
require "./nodist/code_coverage.dat";
if ($Opt_Stage <= 0) {
print "Stage 0: configure (coverage on)\n";
run("make distclean");
run("./configure --enable-longtests CXX='g++ --coverage'");
run("make -k");
# The optimized versions will not collect good coverage, overwrite them
run("cp bin/verilator_bin_dbg bin/verilator_bin");
run("cp bin/verilator_coverage_bin_dbg bin/verilator_coverage_bin");
}
if ($Opt_Stage <= 1) {
print "Stage 1: make examples (with coverage on)\n";
run("make examples");
}
my $cc_dir = "nodist/obj_dir/coverage";
if ($Opt_Stage <= 2) {
print "Stage 2: Create info files under $cc_dir\n";
mkpath($cc_dir);
mkpath("$cc_dir/info");
my $dats = `find . -print | grep .gcda`;
my %dirs;
foreach my $dat (split '\n', $dats) {
$dat =~ s!/[^/]+$!!;
$dirs{$dat} = 1;
}
foreach my $dir (sort keys %dirs) {
(my $outname = $dir) =~ s![^a-zA-Z0-9]+!_!g;
run("cd $cc_dir/info ; lcov -c -d ../../../$dir -o app_test_${outname}.info");
}
}
if ($Opt_Stage <= 3) {
# lcov doesn't have a control file to override single lines, so replicate the sources
print "Stage 3: Clone sources under $cc_dir\n";
clone_sources($cc_dir);
}
if ($Opt_Stage <= 4) {
print "Stage 4: Copy .gcno files\n";
my $dats = `find . -print | grep .gcno`;
foreach my $dat (split '\n', $dats) {
next if $dat =~ /$cc_dir/;
my $outdat = $cc_dir."/".$dat;
#print "cp $dat, $outdat);\n";
cp($dat, $outdat);
}
}
if ($Opt_Stage <= 5) {
print "Stage 5: Combine data files\n";
run("cd $cc_dir ; lcov -c -i -d src/obj_dbg -o app_base.info");
run("cd $cc_dir ; lcov -a app_base.info -o app_total.info");
my $infos = `cd $cc_dir ; find info -print | grep .info`;
my $comb = "";
my @infos = (split /\n/, $infos);
foreach my $info (@infos) {
$comb .= " -a $info";
# Need to batch them to avoid overrunning shell command length limit
if (length($comb) > 10000 || $info eq $infos[$#infos]) {
run("cd $cc_dir ; lcov -a app_total.info $comb -o app_total.info");
$comb = "";
}
}
}
if ($Opt_Stage <= 6) {
print "Stage 6: Filter processed source files\n";
my $cmd = '';
foreach my $glob (@Remove_Sources) {
$cmd .= " '$glob'";
}
run("cd $cc_dir ; lcov --remove app_total.info $cmd -o app_total.info");
}
if ($Opt_Stage <= 7) {
print "Stage 7: Create HTML\n";
cleanup_abs_paths($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info");
run("cd $cc_dir ; genhtml app_total.info --demangle-cpp"
." --rc lcov_branch_coverage=1 --rc genhtml_hi_limit=100 --output-directory html");
}
if ($Opt_Stage <= 9) {
print "*-* All Finished *-*\n";
}
}
sub clone_sources {
my $cc_dir = shift;
my $excluded_lines = 0;
foreach my $glob (@Source_Globs) {
foreach my $infile (glob $glob) {
$infile !~ m!^/!
or die "%Error: source globs should be relative not absolute filenames,";
my $outfile = $cc_dir."/".$infile;
(my $outpath = $outfile) =~ s!/[^/]*$!!;
mkpath($outpath);
my $fh = IO::File->new("<$infile") or die "%Error: $! $infile,";
my $ofh = IO::File->new(">$outfile") or die "%Error: $! $outfile,";
my $lineno = 0;
while (defined(my $line = $fh->getline)) {
$lineno++;
chomp $line;
if ($line !~ m!// LCOV_EXCL_LINE!
&& $line =~ /$Exclude_Line_Regexp/) {
$line .= " //code_coverage: // LCOV_EXCL_LINE\n";
$excluded_lines++;
#print "$infile:$lineno: $line";
} else {
}
$ofh->print("$line\n");
}
}
}
print "Source code lines automatically LCOV_EXCL_LINE'ed: $excluded_lines\n";
}
sub cleanup_abs_paths {
my $cc_dir = shift;
my $infile = shift;
my $outfile = shift;
my $fh = IO::File->new("<$infile") or die "%Error: $! $infile,";
my @lines;
while (defined(my $line = $fh->getline)) {
if ($line =~ m!^SF:/!) {
$line =~ s!$ENV{VERILATOR_ROOT}/!!;
$line =~ s!$cc_dir/!!;
}
push @lines, $line;
}
my $ofh = IO::File->new(">$outfile") or die "%Error: $! $outfile,";
$ofh->print(@lines);
}
#######################################################################
# .dat file callbacks
sub exclude_line_regexp {
$Exclude_Line_Regexp = shift;
}
sub remove_source {
my @srcs = @_;
push @Remove_Sources, @srcs;
}
sub source_globs {
my @dirs = @_;
push @Source_Globs, @dirs;
}
#######################################################################
sub run {
# Run a system command, check errors
my $command = shift;
print "\t$command\n";
system "$command";
my $status = $?;
($status == 0) or die "%Error: Command Failed $command, $status, stopped";
}
#######################################################################
__END__
=pod
=head1 NAME
code_coverage - Build and collect Verilator coverage
=head1 SYNOPSIS
cd $VERILATOR_ROOT
nodist/code_coverage
=head1 DESCRIPTION
code_coverage builds Verilator with C++ coverage support and runs tests
with coverage enabled.
This will rebuild the current object files.
=head1 ARGUMENTS
=over 4
=item --help
Displays this message and program version and exits.
=item -stage I<stage>
Runs a specific stage (see the script).
=back
=head1 DISTRIBUTION
Copyright 2019-2019 by Wilson Snyder. This package 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.
=head1 AUTHORS
Wilson Snyder <wsnyder@wsnyder.org>
=head1 SEE ALSO
C<lcov>
=cut
######################################################################
### Local Variables:
### compile-command: "cd .. ; nodist/code_coverage "
### End:

42
nodist/code_coverage.dat Normal file
View File

@ -0,0 +1,42 @@
# -*- Perl -*-
# DESCRIPTION: Verilator: Internal C++ code lcov control file
#
# Copyright 2019-2019 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.
source_globs("src/*.cpp",
"src/*.h",
"src/*.l",
"src/*.y",
"src/obj_dbg/*.h",
"src/obj_dbg/*.cpp",
"include/*.c",
"include/*.cpp",
"include/*.h",
"include/*/*.h",
"include/*/*.cpp",
"include/*/*.c",
);
remove_source("/usr/include/*");
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");
remove_source("*include/gtkwave/*");
# Something wrong in generation, unfortunately as would like this
#genhtml: ERROR: cannot read /svaha/wsnyder/SandBox/homecvs/v4/verilator/src/obj_dbg/verilog.y
#remove_source("*/src/obj_dbg/verilog.y");
remove_source("*test_regress/*");
remove_source("*examples/*");
exclude_line_regexp(qr/(\bv3fatalSrc\b|\bVL_UNCOVERABLE\b)/);
1;

View File

@ -77,7 +77,7 @@ private:
&& VN_IS(sensesp->sensesp(), SenItem)
&& VN_CAST(sensesp->sensesp(), SenItem)->isNever()) {
// Never executing. Kill it.
if (sensesp->sensesp()->nextp()) {
if (VL_UNCOVERABLE(sensesp->sensesp()->nextp())) {
nodep->v3fatalSrc("Never senitem should be alone, else the never should be eliminated.");
}
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
@ -115,22 +115,22 @@ private:
// No need to do statements under it, they're already moved.
//iterateChildren(nodep);
}
virtual void visit(AstInitial* nodep) {
virtual void visit(AstInitial* nodep) { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstAssignAlias* nodep) {
virtual void visit(AstAssignAlias* nodep) { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstAssignW* nodep) {
virtual void visit(AstAssignW* nodep) { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstAlways* nodep) {
virtual void visit(AstAlways* nodep) { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstAlwaysPublic* nodep) {
virtual void visit(AstAlwaysPublic* nodep) { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstFinal* nodep) {
virtual void visit(AstFinal* nodep) { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been deleted");
}
// Empty visitors, speed things up

View File

@ -772,14 +772,14 @@ void AstNode::iterateAndNext(AstNVisitor& v) {
// there's no lower level reason yet though the back must exist.
AstNode* nodep = this;
#ifdef VL_DEBUG // Otherwise too hot of a function for debug
if (VL_UNLIKELY(nodep && !nodep->m_backp)) nodep->v3fatalSrc("iterateAndNext node has no back");
if (VL_UNCOVERABLE(nodep && !nodep->m_backp)) nodep->v3fatalSrc("iterateAndNext node has no back");
#endif
if (nodep) ASTNODE_PREFETCH(nodep->m_nextp);
while (nodep) { // effectively: if (!this) return; // Callers rely on this
if (nodep->m_nextp) ASTNODE_PREFETCH(nodep->m_nextp->m_nextp);
AstNode* niterp = nodep; // This address may get stomped via m_iterpp if the node is edited
// Desirable check, but many places where multiple iterations are OK
//if (VL_UNLIKELY(niterp->m_iterpp)) niterp->v3fatalSrc("IterateAndNext under iterateAndNext may miss edits");
//if (VL_UNCOVERABLE(niterp->m_iterpp)) niterp->v3fatalSrc("IterateAndNext under iterateAndNext may miss edits");
// Optimization note: Doing PREFETCH_RW on m_iterpp is a net even
// cppcheck-suppress nullPointer
niterp->m_iterpp = &niterp;
@ -973,21 +973,21 @@ void AstNode::checkTree() {
}
}
void AstNode::dumpGdb() { // For GDB only
dumpGdbHeader();
cout<<" "; dump(cout); cout<<endl;
void AstNode::dumpGdb() { // For GDB only // LCOV_EXCL_LINE
dumpGdbHeader(); // LCOV_EXCL_LINE
cout<<" "; dump(cout); cout<<endl; // LCOV_EXCL_LINE
}
void AstNode::dumpGdbHeader() const { // For GDB only
dumpPtrs(cout);
cout<<" Fileline = "<<fileline()<<endl;
void AstNode::dumpGdbHeader() const { // For GDB only // LCOV_EXCL_LINE
dumpPtrs(cout); // LCOV_EXCL_LINE
cout<<" Fileline = "<<fileline()<<endl; // LCOV_EXCL_LINE
}
void AstNode::dumpTreeGdb() { // For GDB only
dumpGdbHeader();
dumpTree(cout);
void AstNode::dumpTreeGdb() { // For GDB only // LCOV_EXCL_LINE
dumpGdbHeader(); // LCOV_EXCL_LINE
dumpTree(cout); // LCOV_EXCL_LINE
}
void AstNode::dumpTreeFileGdb(const char* filenamep) { // For GDB only
string filename = filenamep ? filenamep : v3Global.debugFilename("debug.tree", 98);
v3Global.rootp()->dumpTreeFile(filename);
void AstNode::dumpTreeFileGdb(const char* filenamep) { // For GDB only // LCOV_EXCL_LINE
string filename = filenamep ? filenamep : v3Global.debugFilename("debug.tree", 98); // LCOV_EXCL_LINE
v3Global.rootp()->dumpTreeFile(filename); // LCOV_EXCL_LINE
}
void AstNode::checkIter() const {

View File

@ -51,7 +51,7 @@ typedef std::set<int> MTaskIdSet; // Set of mtaskIds for Var sorting
//######################################################################
// For broken() function, return error string if have a match
#define BROKEN_RTN(test) do { if (VL_UNLIKELY(test)) return # test; } while(0)
#define BROKEN_RTN(test) do { if (VL_UNCOVERABLE(test)) return # test; } while(0)
// (V)erilator (N)ode is: True if AstNode is of a a given AstType
#define VN_IS(nodep,nodetypename) (AstNode::privateIs ## nodetypename(nodep))

View File

@ -76,7 +76,7 @@ const char* AstNodeClassDType::broken() const {
exists.insert(itemp);
}
for (MemberNameMap::const_iterator it=m_members.begin(); it!=m_members.end(); ++it) {
if (VL_UNLIKELY(exists.find(it->second) == exists.end())) {
if (VL_UNCOVERABLE(exists.find(it->second) == exists.end())) {
this->v3error("Internal: Structure member broken: "<<it->first);
return "member broken";
}

View File

@ -303,7 +303,7 @@ private:
}
}
string spaces(int level) { string out; while (level--) out += " "; return out; }
string spaces(int level) { string out; while (level--) out += " "; return out; } // LCOV_EXCL_LINE
string pad(unsigned column, const string& in) {
string out = in;

View File

@ -1570,10 +1570,10 @@ void EmitCStmts::displayArg(AstNode* dispp, AstNode** elistp, bool isScan,
const string& vfmt, char fmtLetter) {
// Print display argument, edits elistp
AstNode* argp = *elistp;
if (!argp) {
if (VL_UNCOVERABLE(!argp)) {
// expectDisplay() checks this first, so internal error if found here
dispp->v3error("Internal: Missing arguments for $display-like format");
return;
dispp->v3error("Internal: Missing arguments for $display-like format"); // LCOV_EXCL_LINE
return; // LCOV_EXCL_LINE
}
if (argp->widthMin() > VL_VALUE_STRING_MAX_WIDTH) {
dispp->v3error("Exceeded limit of "+cvtToStr(VL_VALUE_STRING_MAX_WIDTH)+" bits for any $display-like arguments");
@ -1673,9 +1673,9 @@ void EmitCStmts::displayNode(AstNode* nodep, AstScopeName* scopenamep,
}
}
}
if (elistp != NULL) {
if (VL_UNCOVERABLE(elistp)) {
// expectFormat also checks this, and should have found it first, so internal
elistp->v3error("Internal: Extra arguments for $display-like format");
elistp->v3error("Internal: Extra arguments for $display-like format"); // LCOV_EXCL_LINE
}
displayEmit(nodep, isScan);
}
@ -1722,7 +1722,9 @@ void EmitCImp::emitVarReset(AstVar* varp) {
arrayp;
arrayp = VN_CAST(arrayp->subDTypep()->skipRefp(), UnpackArrayDType)) {
int vecnum = vects++;
if (arrayp->msb() < arrayp->lsb()) varp->v3fatalSrc("Should have swapped msb & lsb earlier.");
if (VL_UNCOVERABLE(arrayp->msb() < arrayp->lsb())) {
varp->v3fatalSrc("Should have swapped msb & lsb earlier.");
}
string ivar = string("__Vi")+cvtToStr(vecnum);
// MSVC++ pre V7 doesn't support 'for (int ...)', so declare in sep block
puts("{ int __Vi"+cvtToStr(vecnum)+"="+cvtToStr(0)+";");
@ -1960,7 +1962,7 @@ void EmitCImp::emitSavableImp(AstNodeModule* modp) {
arrayp;
arrayp = VN_CAST(elementp, UnpackArrayDType)) {
int vecnum = vects++;
if (arrayp->msb() < arrayp->lsb()) {
if (VL_UNCOVERABLE(arrayp->msb() < arrayp->lsb())) {
varp->v3fatalSrc("Should have swapped msb & lsb earlier.");
}
string ivar = string("__Vi")+cvtToStr(vecnum);
@ -2060,7 +2062,7 @@ void EmitCImp::emitSensitives() {
arrayp;
arrayp = VN_CAST(arrayp->subDTypep()->skipRefp(), UnpackArrayDType)) {
int vecnum = vects++;
if (arrayp->msb() < arrayp->lsb()) {
if (VL_UNCOVERABLE(arrayp->msb() < arrayp->lsb())) {
varp->v3fatalSrc("Should have swapped msb & lsb earlier.");
}
string ivar = string("__Vi")+cvtToStr(vecnum);

View File

@ -228,7 +228,7 @@ public:
}
//--------------------
virtual void visit(AstNode* nodep) {
virtual void visit(AstNode* nodep) { // LCOV_EXCL_LINE
nodep->v3fatalSrc("No visitors implemented.");
}

View File

@ -73,8 +73,7 @@ void V3Error::init() {
s_describedEachWarn[i] = false;
s_pretendError[i] = V3ErrorCode(i).pretendError();
}
if (string(V3ErrorCode(V3ErrorCode::_ENUM_MAX).ascii()) != " MAX") {
if (VL_UNCOVERABLE(string(V3ErrorCode(V3ErrorCode::_ENUM_MAX).ascii()) != " MAX")) {
v3fatalSrc("Enum table in V3ErrorCode::EC_ascii() is munged");
}
}

View File

@ -301,8 +301,8 @@ inline void v3errorEndFatal(std::ostringstream& sstr) {
::v3errorEndFatal((V3Error::v3errorPrep(V3ErrorCode::EC_FATAL), \
(V3Error::v3errorStr()<<msg), V3Error::v3errorStr()));
#define UINFO(level,stmsg) {if(VL_UNLIKELY(debug()>=(level))) { cout<<"- "<<V3Error::lineStr(__FILE__,__LINE__)<<stmsg; }}
#define UINFONL(level,stmsg) {if(VL_UNLIKELY(debug()>=(level))) { cout<<stmsg; } }
#define UINFO(level,stmsg) {if (VL_UNCOVERABLE(debug()>=(level))) { cout<<"- "<<V3Error::lineStr(__FILE__,__LINE__)<<stmsg; }}
#define UINFONL(level,stmsg) {if (VL_UNCOVERABLE(debug()>=(level))) { cout<<stmsg; } }
#ifdef VL_DEBUG
# define UDEBUGONLY(stmts) {stmts}
@ -310,10 +310,10 @@ inline void v3errorEndFatal(std::ostringstream& sstr) {
# define UDEBUGONLY(stmts) {if (0) {stmts}}
#endif
#define UASSERT(condition,stmsg) { if (VL_UNLIKELY(!(condition))) { v3fatalSrc(stmsg); }}
#define UASSERT(condition,stmsg) { if (VL_UNCOVERABLE(!(condition))) { v3fatalSrc(stmsg); }}
// For use in V3Ast static functions only
#define UASSERT_STATIC(condition,stmsg) \
{ if (VL_UNLIKELY(!(condition))) { \
{ if (VL_UNCOVERABLE(!(condition))) { \
std::cerr<<"Internal Error: "<<__FILE__<<":"<<std::dec<<__LINE__<<":"<<(stmsg)<<std::endl; abort(); } }
// Check self test values for expected value. Safe from side-effects.
// Type argument can be removed when go to C++11 (use auto).

View File

@ -239,7 +239,7 @@ private:
}
bool expandWide(AstNodeAssign* nodep, AstArraySel* rhsp) {
UINFO(8," Wordize ASSIGN(ARRAYSEL) "<<nodep<<endl);
if (VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType)) {
if (VL_UNCOVERABLE(VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType))) {
nodep->v3fatalSrc("ArraySel with unpacked arrays should have been removed in V3Slice");
}
for (int w=0; w<nodep->widthWords(); w++) {

View File

@ -94,7 +94,7 @@ void GraphPathChecker::initHalfCriticalPaths(GraphWay way, bool checkOnly) {
GraphPCNode* ourUserp = static_cast<GraphPCNode*>(vertexp->userp());
if (checkOnly) {
if (ourUserp->m_cp[way] != critPathCost) {
if (VL_UNCOVERABLE(ourUserp->m_cp[way] != critPathCost)) {
vertexp->v3fatalSrc("Validation of critical paths failed");
}
} else {

View File

@ -60,7 +60,9 @@ private:
// Decrement blocking edges count, return true if the vertex is
// newly unblocked
bool unblock() {
if (m_numBlockingEdges <= 0) vertexp()->v3fatalSrc("Underflow of blocking edges");
if (VL_UNCOVERABLE(m_numBlockingEdges <= 0)) {
vertexp()->v3fatalSrc("Underflow of blocking edges");
}
m_numBlockingEdges--;
return (m_numBlockingEdges == 0);
}
@ -208,7 +210,7 @@ private:
typename WaitingVertices::iterator it =
m_waitingVertices.find(toVertexp);
if (it == m_waitingVertices.end()) {
if (VL_UNCOVERABLE(it == m_waitingVertices.end())) {
toVertexp->v3fatalSrc("Found edge into vertex not in waiting list.");
}
if (it->second.unblock()) {
@ -223,7 +225,7 @@ private:
typename WaitingVertices::iterator it =
m_waitingVertices.find(fromVertexp);
if (it == m_waitingVertices.end()) {
if (VL_UNCOVERABLE(it == m_waitingVertices.end())) {
fromVertexp->v3fatalSrc("Found edge into vertex not in waiting list.");
}
if (it->second.unblock()) {

View File

@ -124,7 +124,7 @@ private:
if (nodep->pragType() == AstPragmaType::INLINE_MODULE) {
//UINFO(0,"PRAG MARK "<<m_modp<<endl);
if (!m_modp) {
nodep->v3error("Inline pragma not under a module");
nodep->v3error("Inline pragma not under a module"); // LCOV_EXCL_LINE
} else if (m_modp->user2() == CIL_MAYBE
|| m_modp->user2() == CIL_NOTSOFT) {
m_modp->user2(CIL_USER);
@ -132,7 +132,7 @@ private:
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep); // Remove so don't propagate to upper cell...
} else if (nodep->pragType() == AstPragmaType::NO_INLINE_MODULE) {
if (!m_modp) {
nodep->v3error("Inline pragma not under a module");
nodep->v3error("Inline pragma not under a module"); // LCOV_EXCL_LINE
} else {
cantInline("Pragma NO_INLINE_MODULE", false);
}

View File

@ -331,7 +331,7 @@ V3Number& V3Number::setLongS(vlsint32_t value) {
return *this;
}
V3Number& V3Number::setDouble(double value) {
if (VL_UNLIKELY(width()!=64)) {
if (VL_UNCOVERABLE(width()!=64)) {
v3fatalSrc("Real operation on wrong sized number");
}
m_double = true;
@ -685,11 +685,8 @@ uint32_t V3Number::toUInt() const {
}
double V3Number::toDouble() const {
if (VL_UNLIKELY(!isDouble())) {
v3fatalSrc("Real conversion on non-real number");
}
if (VL_UNLIKELY(width()!=64)) {
v3fatalSrc("Real operation on wrong sized number");
if (VL_UNCOVERABLE(!isDouble() || width()!=64)) {
v3fatalSrc("Real operation on wrong sized/non-real number");
}
union { double d; uint32_t u[2]; } u;
u.u[0] = m_value[0]; u.u[1] = m_value[1];

View File

@ -215,9 +215,9 @@ private:
}
void statePop() {
m_states.pop();
if (m_states.empty()) {
error("InternalError: Pop of parser state with nothing on stack");
m_states.push(ps_TOP);
if (VL_UNCOVERABLE(m_states.empty())) {
error("InternalError: Pop of parser state with nothing on stack"); // LCOV_EXCL_LINE
m_states.push(ps_TOP); // LCOV_EXCL_LINE
}
}
void stateChange(ProcState state) {

View File

@ -125,7 +125,7 @@ public:
return;
}
// Try the previous value?
if (m_valIt == m_sbvmp->m_vals.begin()) {
if (VL_UNCOVERABLE(m_valIt == m_sbvmp->m_vals.begin())) {
// No more values but it's not defined to decrement an
// iterator past the beginning.
v3fatalSrc("Decremented iterator past beginning");

View File

@ -161,7 +161,7 @@ class SliceVisitor : public AstNVisitor {
}
virtual void visit(AstInitArray* nodep) {
if (m_assignp) {
if (VL_UNCOVERABLE(m_assignp)) {
nodep->v3fatalSrc("Array initialization should have been removed earlier");
}
}

View File

@ -276,15 +276,15 @@ void VHashSha1::selfTestOne(const string& data, const string& data2,
const string& exp, const string& exp64) {
VHashSha1 digest (data);
if (data2!="") digest.insert(data2);
if (digest.digestHex() != exp) {
std::cerr << "%Error: When hashing '"<<data+data2<<"'"<<endl;
std::cerr << "%Error: got="<<digest.digestHex()<<endl;
std::cerr << "%Error: exp="<<exp<<endl;
if (VL_UNCOVERABLE(digest.digestHex() != exp)) {
std::cerr << "%Error: When hashing '"<<data+data2<<"'"<<endl // LCOV_EXCL_LINE
<< " ... got="<<digest.digestHex()<<endl // LCOV_EXCL_LINE
<< " ... exp="<<exp<<endl; // LCOV_EXCL_LINE
}
if (digest.digestSymbol() != exp64) {
std::cerr << "%Error: When hashing '"<<data+data2<<"'"<<endl;
std::cerr << "%Error: got="<<digest.digestSymbol()<<endl;
std::cerr << "%Error: exp="<<exp64<<endl;
if (VL_UNCOVERABLE(digest.digestSymbol() != exp64)) {
std::cerr << "%Error: When hashing '"<<data+data2<<"'"<<endl // LCOV_EXCL_LINE
<< " ... got="<<digest.digestSymbol()<<endl // LCOV_EXCL_LINE
<< " ... exp="<<exp64<<endl; // LCOV_EXCL_LINE
}
}

View File

@ -598,7 +598,7 @@ void V3TSP::selfTestStates() {
expect.push_back(&s20);
expect.push_back(&s10);
expect.push_back(&s5);
if (expect != result) {
if (VL_UNCOVERABLE(expect != result)) {
for (V3TSP::StateVec::iterator it = result.begin();
it != result.end(); ++it) {
const TspTestState* statep = dynamic_cast<const TspTestState*>(*it);
@ -641,7 +641,7 @@ void V3TSP::selfTestStates() {
expect.push_back(&d);
expect.push_back(&e);
if (expect != result) {
if (VL_UNCOVERABLE(expect != result)) {
for (V3TSP::StateVec::iterator it = result.begin();
it != result.end(); ++it) {
const TspTestState* statep = dynamic_cast<const TspTestState*>(*it);
@ -689,7 +689,7 @@ void V3TSP::selfTestString() {
expect.push_back("2");
expect.push_back("3");
if (expect != result) {
if (VL_UNCOVERABLE(expect != result)) {
for (std::vector<string>::iterator it = result.begin(); it != result.end(); ++it) {
cout<<*it<<" ";
}

View File

@ -4033,7 +4033,7 @@ private:
//----------------------------------------------------------------------
// METHODS - special type detection
void assertAtStatement(AstNode* nodep) {
if (VL_UNLIKELY(m_vup && !m_vup->selfDtm())) {
if (VL_UNCOVERABLE(m_vup && !m_vup->selfDtm())) {
UINFO(1,"-: "<<m_vup<<endl);
nodep->v3fatalSrc("No dtype expected at statement "<<nodep->prettyTypeName());
}

View File

@ -152,7 +152,7 @@ private:
iterateChildren(nodep);
nodep->virtRefDTypep(editOneDType(nodep->virtRefDTypep()));
}
virtual void visit(AstNodePreSel* nodep) {
virtual void visit(AstNodePreSel* nodep) { // LCOV_EXCL_LINE
// This check could go anywhere after V3Param
nodep->v3fatalSrc("Presels should have been removed before this point");
}