verilator/src/V3CoverageJoin.cpp

122 lines
5.0 KiB
C++

// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Netlist (top level) functions
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2003-2024 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
//
//*************************************************************************
// COVERAGEJOIN TRANSFORMATIONS:
// If two COVERTOGGLEs have same VARSCOPE, combine them
//*************************************************************************
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
#include "V3CoverageJoin.h"
#include "V3DupFinder.h"
#include "V3Stats.h"
#include <vector>
VL_DEFINE_DEBUG_FUNCTIONS;
//######################################################################
// CoverageJoin state, as a visitor of each AstNode
class CoverageJoinVisitor final : public VNVisitor {
// NODE STATE
// VNUser4InUse In V3Hasher via V3DupFinder
// STATE - per active
std::vector<AstCoverToggle*> m_toggleps; // List of of all AstCoverToggle's
// STATE - Statistic tracking
VDouble0 m_statToggleJoins; // Statistic tracking
// METHODS
void detectDuplicates() {
UINFO(9, "Finding duplicates\n");
// Note uses user4
V3DupFinder dupFinder; // Duplicate code detection
// Hash all of the original signals we toggle cover
for (AstCoverToggle* nodep : m_toggleps) dupFinder.insert(nodep->origp());
if (dumpLevel() || debug() >= 9)
dupFinder.dumpFile(v3Global.debugFilename("coveragejoin") + ".hash", false);
// Find if there are any duplicates
for (AstCoverToggle* nodep : m_toggleps) {
// nodep->backp() is null if we already detected it's a duplicate and unlinked earlier
if (!nodep->backp()) continue;
// Want to choose a base node, and keep finding duplicates that are identical.
// This prevents making chains where a->b, then c->d, then b->c, as we'll
// find a->b, a->c, a->d directly.
while (true) {
const auto dupit = dupFinder.findDuplicate(nodep->origp());
if (dupit == dupFinder.end()) break;
const AstNode* const duporigp = dupit->second;
// Remove node from comparison so don't hit it again
dupFinder.erase(dupit);
//
// Note dupFinder will point to the original toggle-increment equation (what's
// duplicated), not the covertoggle, but we need to get back to the
// covertoggle which is immediately above, so:
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* 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
// (Not vice-versa as we have the iterator for the found node)
removep->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(removep), removep);
++m_statToggleJoins;
}
}
}
// VISITORS
void visit(AstActive* nodep) override {
m_toggleps.clear();
// Find all Coverage's
iterateChildren(nodep);
// Simplify
detectDuplicates();
}
void visit(AstCoverToggle* nodep) override {
m_toggleps.push_back(nodep);
iterateChildren(nodep);
}
//--------------------
void visit(AstNodeExpr*) override {} // Accelerate
void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit CoverageJoinVisitor(AstNetlist* nodep) { iterate(nodep); }
~CoverageJoinVisitor() override {
V3Stats::addStat("Coverage, Toggle points joined", m_statToggleJoins);
}
};
//######################################################################
// Coverage class functions
void V3CoverageJoin::coverageJoin(AstNetlist* rootp) {
UINFO(2, __FUNCTION__ << ": " << endl);
{ CoverageJoinVisitor{rootp}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("coveragejoin", 0, dumpTreeEitherLevel() >= 3);
}