From 01ef7122e9d5b77fb8151ad2cea01ab5506c8b42 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 30 Jun 2019 22:37:03 -0400 Subject: [PATCH] Internals: Add lcov code coverage markers. --- Makefile.in | 3 +- include/verilated.cpp | 14 +- include/verilated.h | 4 +- include/verilated_threads.cpp | 3 +- include/verilated_vpi.cpp | 6 +- include/verilatedos.h | 1 + nodist/code_coverage | 260 ++++++++++++++++++++++++++++++++++ nodist/code_coverage.dat | 42 ++++++ src/V3ActiveTop.cpp | 14 +- src/V3Ast.cpp | 28 ++-- src/V3Ast.h | 2 +- src/V3AstNodes.cpp | 2 +- src/V3Cdc.cpp | 2 +- src/V3EmitC.cpp | 18 +-- src/V3EmitMk.cpp | 2 +- src/V3Error.cpp | 3 +- src/V3Error.h | 8 +- src/V3Expand.cpp | 2 +- src/V3GraphPathChecker.cpp | 2 +- src/V3GraphStream.h | 8 +- src/V3Inline.cpp | 4 +- src/V3Number.cpp | 9 +- src/V3PreProc.cpp | 6 +- src/V3Scoreboard.h | 2 +- src/V3Slice.cpp | 2 +- src/V3String.cpp | 16 +-- src/V3TSP.cpp | 6 +- src/V3Width.cpp | 2 +- src/V3WidthCommit.h | 2 +- 29 files changed, 388 insertions(+), 85 deletions(-) create mode 100755 nodist/code_coverage create mode 100644 nodist/code_coverage.dat diff --git a/Makefile.in b/Makefile.in index bdc2b4d68..647b3683a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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) diff --git a/include/verilated.cpp b/include/verilated.cpp index fd6eea57c..627ca744e 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -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 diff --git a/include/verilated.h b/include/verilated.h index fb8553c0c..a8d969b8c 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -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; diff --git a/include/verilated_threads.cpp b/include/verilated_threads.cpp index de88a8a4b..92539640e 100644 --- a/include/verilated_threads.cpp +++ b/include/verilated_threads.cpp @@ -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 } } } diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index 7b5db2d7b..1d37151e7 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -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"); } diff --git a/include/verilatedos.h b/include/verilatedos.h index 68477daa3..8cb43e6cb 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -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 diff --git a/nodist/code_coverage b/nodist/code_coverage new file mode 100755 index 000000000..7b46ae17c --- /dev/null +++ b/nodist/code_coverage @@ -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 + +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 + +=head1 SEE ALSO + +C + +=cut + +###################################################################### +### Local Variables: +### compile-command: "cd .. ; nodist/code_coverage " +### End: diff --git a/nodist/code_coverage.dat b/nodist/code_coverage.dat new file mode 100644 index 000000000..35b67649f --- /dev/null +++ b/nodist/code_coverage.dat @@ -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; diff --git a/src/V3ActiveTop.cpp b/src/V3ActiveTop.cpp index 828c9fd64..de9da5e24 100644 --- a/src/V3ActiveTop.cpp +++ b/src/V3ActiveTop.cpp @@ -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 diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index e35dc8d22..13635bc14 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -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<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 { diff --git a/src/V3Ast.h b/src/V3Ast.h index cf15d06eb..6f1cae9ba 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -51,7 +51,7 @@ typedef std::set 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)) diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 4a5dbe894..2883999ea 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -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: "<first); return "member broken"; } diff --git a/src/V3Cdc.cpp b/src/V3Cdc.cpp index 8d5f6c572..49c3cbc69 100644 --- a/src/V3Cdc.cpp +++ b/src/V3Cdc.cpp @@ -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; diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index f5462978b..8b601261f 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -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); diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index de2cd7c6b..5339e7953 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -228,7 +228,7 @@ public: } //-------------------- - virtual void visit(AstNode* nodep) { + virtual void visit(AstNode* nodep) { // LCOV_EXCL_LINE nodep->v3fatalSrc("No visitors implemented."); } diff --git a/src/V3Error.cpp b/src/V3Error.cpp index c8535f1be..bbe31a140 100644 --- a/src/V3Error.cpp +++ b/src/V3Error.cpp @@ -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"); } } diff --git a/src/V3Error.h b/src/V3Error.h index 97a61ae36..5eadec8d0 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -301,8 +301,8 @@ inline void v3errorEndFatal(std::ostringstream& sstr) { ::v3errorEndFatal((V3Error::v3errorPrep(V3ErrorCode::EC_FATAL), \ (V3Error::v3errorStr()<=(level))) { cout<<"- "<=(level))) { cout<=(level))) { cout<<"- "<=(level))) { cout<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; wwidthWords(); w++) { diff --git a/src/V3GraphPathChecker.cpp b/src/V3GraphPathChecker.cpp index c61de4663..5996ad32a 100644 --- a/src/V3GraphPathChecker.cpp +++ b/src/V3GraphPathChecker.cpp @@ -94,7 +94,7 @@ void GraphPathChecker::initHalfCriticalPaths(GraphWay way, bool checkOnly) { GraphPCNode* ourUserp = static_cast(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 { diff --git a/src/V3GraphStream.h b/src/V3GraphStream.h index 5f1f18ad8..b3d5fa554 100644 --- a/src/V3GraphStream.h +++ b/src/V3GraphStream.h @@ -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()) { diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index 7d1d2820a..77583b075 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -124,7 +124,7 @@ private: if (nodep->pragType() == AstPragmaType::INLINE_MODULE) { //UINFO(0,"PRAG MARK "<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); } diff --git a/src/V3Number.cpp b/src/V3Number.cpp index 0f5ea3a98..37a75e778 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -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]; diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index daaf87f82..be27ee6f2 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -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) { diff --git a/src/V3Scoreboard.h b/src/V3Scoreboard.h index 33dc6052a..9dc3aaa58 100644 --- a/src/V3Scoreboard.h +++ b/src/V3Scoreboard.h @@ -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"); diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp index 5a1be7966..589f5799a 100644 --- a/src/V3Slice.cpp +++ b/src/V3Slice.cpp @@ -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"); } } diff --git a/src/V3String.cpp b/src/V3String.cpp index 505a08b7c..af56de8d6 100644 --- a/src/V3String.cpp +++ b/src/V3String.cpp @@ -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 '"<::iterator it = result.begin(); it != result.end(); ++it) { cout<<*it<<" "; } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index e7ef5d2b7..5db742e51 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -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,"-: "<v3fatalSrc("No dtype expected at statement "<prettyTypeName()); } diff --git a/src/V3WidthCommit.h b/src/V3WidthCommit.h index 0a5efbbd2..bd9eb69a6 100644 --- a/src/V3WidthCommit.h +++ b/src/V3WidthCommit.h @@ -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"); }